From cec4c0b87aedd817d7bd8c24ea3530482688624e Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sun, 20 Jul 2014 11:37:56 +0200
Subject: [PATCH 2/2] WIP bluetooth userland

---
 Makefile_upgrade.inc                          |   16 +
 etc/Makefile                                  |    4 +-
 etc/bluetooth/Makefile                        |   15 +-
 etc/bluetooth/hcsecd.conf                     |   56 +
 etc/bluetooth/hosts                           |    6 +-
 etc/bluetooth/protocols                       |    7 +-
 etc/defaults/bluetooth.device.conf            |  111 +
 etc/defaults/rc.conf                          |   39 +-
 etc/mtree/BSD.include.dist                    |    6 +-
 etc/rc.d/Makefile                             |   13 +-
 etc/rc.d/bluetooth                            |  365 +++
 etc/rc.d/btconfig                             |   67 -
 etc/rc.d/bthcid                               |   19 -
 etc/rc.d/bthidd                               |   33 +
 etc/rc.d/hcsecd                               |   24 +
 etc/rc.d/sdpd                                 |   13 +-
 etc/rc.d/ubthidhci                            |   40 +
 include/Makefile                              |    5 +-
 lib/libbluetooth/Makefile                     |   34 +-
 lib/libbluetooth/bluetooth.3                  |  499 +++-
 lib/libbluetooth/bluetooth.c                  |   31 +-
 lib/libbluetooth/bluetooth.h                  |  215 +-
 lib/libbluetooth/dev.c                        |   95 +
 lib/libbluetooth/devaddr.c                    |  116 -
 lib/libbluetooth/hci.c                        |  734 +++++
 lib/libsdp/Makefile                           |   16 +-
 lib/libsdp/sdp-int.h                          |    8 +-
 lib/libsdp/sdp.3                              |   32 +-
 lib/libsdp/sdp.h                              |  429 +--
 lib/libsdp/search.c                           |   38 +-
 lib/libsdp/service.c                          |   65 +-
 lib/libsdp/session.c                          |   90 +-
 lib/libsdp/util.c                             |  102 +-
 share/examples/etc/README.examples            |    1 +
 share/man/man4/Makefile                       |    2 -
 share/man/man4/bluetooth.4                    |  392 ---
 share/man/man4/ng_bluetooth.4                 |  112 +
 share/man/man4/ng_bt3c.4                      |  129 +
 share/man/man4/ng_btsocket.4                  |  354 +++
 share/man/man4/ng_h4.4                        |  123 +
 share/man/man4/ng_hci.4                       |  387 +++
 share/man/man4/ng_l2cap.4                     |  422 +++
 share/man/man4/ng_ubt.4                       |  125 +
 share/man/man4/ubt.4                          |  149 -
 share/man/man4/ubtbcmfw.4                     |  108 +
 share/man/man4/usb.4                          |    5 +-
 share/man/man5/bluetooth.device.conf.5        |  186 ++
 share/man/man5/bluetooth.hosts.5              |   63 +
 share/man/man5/bluetooth.protocols.5          |   62 +
 share/man/man5/rc.conf.5                      |  158 +-
 sys/Makefile                                  |    2 +-
 sys/Makefile.modules                          |    2 +-
 sys/conf/files                                |   19 -
 sys/config/LINT64                             |    3 -
 sys/netbt/Makefile                            |   10 -
 sys/netbt/bluetooth.h                         |  158 -
 sys/netbt/bt_input.c                          |   41 -
 sys/netbt/bt_proto.c                          |  235 --
 sys/netbt/hci.h                               | 2579 -----------------
 sys/netbt/hci_event.c                         | 1086 -------
 sys/netbt/hci_ioctl.c                         |  301 --
 sys/netbt/hci_link.c                          | 1083 -------
 sys/netbt/hci_misc.c                          |  181 --
 sys/netbt/hci_socket.c                        | 1034 -------
 sys/netbt/hci_unit.c                          |  551 ----
 sys/netbt/l2cap.h                             |  493 ----
 sys/netbt/l2cap_lower.c                       |  205 --
 sys/netbt/l2cap_misc.c                        |  255 --
 sys/netbt/l2cap_signal.c                      | 1154 --------
 sys/netbt/l2cap_socket.c                      |  515 ----
 sys/netbt/l2cap_upper.c                       |  555 ----
 sys/netbt/rfcomm.h                            |  432 ---
 sys/netbt/rfcomm_dlc.c                        |  414 ---
 sys/netbt/rfcomm_session.c                    | 1697 -----------
 sys/netbt/rfcomm_socket.c                     |  514 ----
 sys/netbt/rfcomm_upper.c                      |  567 ----
 sys/netbt/sco.h                               |   90 -
 sys/netbt/sco_socket.c                        |  473 ---
 sys/netbt/sco_upper.c                         |  360 ---
 usr.bin/Makefile                              |    4 +-
 usr.bin/bthost/Makefile                       |    9 +
 usr.bin/bthost/bthost.1                       |  115 +
 usr.bin/bthost/bthost.c                       |  142 +
 usr.bin/btpin/Makefile                        |   10 -
 usr.bin/btpin/btpin.1                         |   92 -
 usr.bin/btpin/btpin.c                         |  151 -
 usr.bin/btsockstat/Makefile                   |   12 +
 usr.bin/btsockstat/btsockstat.1               |   83 +
 usr.bin/btsockstat/btsockstat.c               |  646 +++++
 usr.bin/rfcomm_sppd/Makefile                  |   10 +-
 usr.bin/rfcomm_sppd/rfcomm_sdp.c              |   72 +-
 usr.bin/rfcomm_sppd/rfcomm_sdp.h              |   40 -
 usr.bin/rfcomm_sppd/rfcomm_sppd.1             |  243 +-
 usr.bin/rfcomm_sppd/rfcomm_sppd.c             |  723 +++--
 usr.bin/sdpquery/Makefile                     |   14 -
 usr.bin/sdpquery/sdpquery.1                   |  210 --
 usr.bin/sdpquery/sdpquery.c                   |  152 -
 usr.bin/sdpquery/sdpquery.h                   |   43 -
 usr.sbin/Makefile                             |   15 +-
 usr.sbin/ath3kfw/Makefile                     |    8 +
 usr.sbin/ath3kfw/ath3kfw.8                    |   78 +
 usr.sbin/ath3kfw/ath3kfw.c                    |  297 ++
 usr.sbin/bcmfw/BCM-LEGAL.txt                  |    8 +
 usr.sbin/bcmfw/Makefile                       |    8 +
 usr.sbin/bcmfw/README                         |   22 +
 usr.sbin/bcmfw/bcmfw.8                        |  105 +
 usr.sbin/bcmfw/bcmfw.c                        |  308 ++
 usr.sbin/bt3cfw/Makefile                      |   11 +
 usr.sbin/bt3cfw/bt3cfw.8                      |   73 +
 usr.sbin/bt3cfw/bt3cfw.c                      |  228 ++
 usr.sbin/btconfig/Makefile                    |   10 -
 usr.sbin/btconfig/btconfig.8                  |  178 --
 usr.sbin/btconfig/btconfig.c                  | 1173 --------
 usr.sbin/bthcid/Makefile                      |   12 -
 usr.sbin/bthcid/bthcid.8                      |  173 --
 usr.sbin/bthcid/bthcid.c                      |  232 --
 usr.sbin/bthcid/bthcid.h                      |   91 -
 usr.sbin/bthcid/client.c                      |  346 ---
 usr.sbin/bthcid/config.c                      |  143 -
 usr.sbin/bthcid/hci.c                         |  355 ---
 usr.sbin/bthidcontrol/Makefile                |   15 +
 usr.sbin/bthidcontrol/bthidcontrol.8          |  102 +
 usr.sbin/bthidcontrol/bthidcontrol.c          |  215 ++
 usr.sbin/bthidcontrol/bthidcontrol.h          |   50 +
 usr.sbin/bthidcontrol/hid.c                   |  214 ++
 usr.sbin/bthidcontrol/sdp.c                   |  434 +++
 usr.sbin/bthidd/Makefile                      |   18 +
 usr.sbin/bthidd/bthid_config.h                |   70 +
 usr.sbin/bthidd/bthidd.8                      |  127 +
 usr.sbin/bthidd/bthidd.c                      |  266 ++
 usr.sbin/bthidd/bthidd.conf.sample            |   72 +
 usr.sbin/bthidd/bthidd.h                      |   93 +
 usr.sbin/bthidd/client.c                      |  256 ++
 usr.sbin/bthidd/hid.c                         |  408 +++
 usr.sbin/bthidd/kbd.c                         |  580 ++++
 usr.sbin/bthidd/kbd.h                         |   41 +
 usr.sbin/bthidd/lexer.l                       |  106 +
 usr.sbin/bthidd/parser.y                      |  475 +++
 usr.sbin/bthidd/server.c                      |  349 +++
 usr.sbin/bthidd/session.c                     |  184 ++
 usr.sbin/btpand/Makefile                      |   13 +
 usr.sbin/btpand/bnep.c                        |  755 +++++
 usr.sbin/btpand/bnep.h                        |   72 +
 usr.sbin/btpand/btpand.8                      |  240 ++
 usr.sbin/btpand/btpand.c                      |  293 ++
 usr.sbin/btpand/btpand.h                      |  212 ++
 usr.sbin/btpand/channel.c                     |  335 +++
 usr.sbin/btpand/client.c                      |  224 ++
 usr.sbin/btpand/event.c                       |  309 ++
 usr.sbin/btpand/event.h                       |  147 +
 usr.sbin/btpand/packet.c                      |  110 +
 usr.sbin/btpand/sdp.c                         |  209 ++
 usr.sbin/btpand/sdp.h                         |   38 +
 usr.sbin/btpand/server.c                      |  289 ++
 usr.sbin/btpand/tap.c                         |  167 ++
 usr.sbin/hccontrol/Makefile                   |   14 +
 usr.sbin/hccontrol/hccontrol.8                |  184 ++
 usr.sbin/hccontrol/hccontrol.c                |  322 ++
 usr.sbin/hccontrol/hccontrol.h                |   79 +
 usr.sbin/hccontrol/host_controller_baseband.c | 1877 ++++++++++++
 usr.sbin/hccontrol/info.c                     |  216 ++
 usr.sbin/hccontrol/link_control.c             |  960 ++++++
 usr.sbin/hccontrol/link_policy.c              |  305 ++
 usr.sbin/hccontrol/node.c                     |  607 ++++
 usr.sbin/hccontrol/send_recv.c                |  184 ++
 usr.sbin/hccontrol/status.c                   |  245 ++
 usr.sbin/hccontrol/util.c                     |  410 +++
 usr.sbin/hcsecd/Makefile                      |   13 +
 usr.sbin/hcsecd/hcsecd.8                      |  128 +
 usr.sbin/hcsecd/hcsecd.c                      |  446 +++
 .../hcsecd/hcsecd.conf                        |   45 +-
 .../bthcid.conf.5 => hcsecd/hcsecd.conf.5}    |   14 +-
 usr.sbin/hcsecd/hcsecd.h                      |   65 +
 usr.sbin/{bthcid => hcsecd}/lexer.l           |    6 +-
 usr.sbin/{bthcid => hcsecd}/parser.y          |  144 +-
 usr.sbin/hcseriald/Makefile                   |   11 +
 usr.sbin/hcseriald/hcseriald.8                |   86 +
 usr.sbin/hcseriald/hcseriald.c                |  268 ++
 usr.sbin/l2control/Makefile                   |   12 +
 usr.sbin/l2control/l2cap.c                    |  313 ++
 usr.sbin/l2control/l2control.8                |   97 +
 usr.sbin/l2control/l2control.c                |  220 ++
 usr.sbin/l2control/l2control.h                |   49 +
 usr.sbin/l2ping/Makefile                      |   11 +
 usr.sbin/l2ping/l2ping.8                      |  114 +
 usr.sbin/l2ping/l2ping.c                      |  292 ++
 usr.sbin/rfcomm_pppd/Makefile                 |   14 +
 usr.sbin/rfcomm_pppd/rfcomm_pppd.8            |  354 +++
 usr.sbin/rfcomm_pppd/rfcomm_pppd.c            |  471 +++
 usr.sbin/sdpcontrol/Makefile                  |   12 +
 usr.sbin/sdpcontrol/sdpcontrol.8              |  118 +
 usr.sbin/sdpcontrol/sdpcontrol.c              |  219 ++
 usr.sbin/sdpcontrol/sdpcontrol.h              |   49 +
 .../sdpquery => usr.sbin/sdpcontrol}/search.c |  293 +-
 usr.sbin/sdpd/Makefile                        |   11 +-
 usr.sbin/sdpd/bgd.c                           |   20 +-
 usr.sbin/sdpd/dun.c                           |   26 +-
 usr.sbin/sdpd/ftrn.c                          |   22 +-
 usr.sbin/sdpd/gn.c                            |  172 ++
 usr.sbin/sdpd/hf.c                            |  162 --
 usr.sbin/sdpd/hset.c                          |  143 -
 usr.sbin/sdpd/irmc.c                          |   24 +-
 usr.sbin/sdpd/irmc_command.c                  |   22 +-
 usr.sbin/sdpd/lan.c                           |   36 +-
 usr.sbin/sdpd/log.c                           |   10 +-
 usr.sbin/sdpd/log.h                           |   24 +-
 usr.sbin/sdpd/main.c                          |   26 +-
 usr.sbin/sdpd/nap.c                           |  209 ++
 usr.sbin/sdpd/opush.c                         |   24 +-
 usr.sbin/sdpd/panu.c                          |  172 ++
 usr.sbin/sdpd/profile.c                       |  160 +-
 usr.sbin/sdpd/profile.h                       |   19 +-
 usr.sbin/sdpd/provider.c                      |   57 +-
 usr.sbin/sdpd/provider.h                      |   52 +-
 usr.sbin/sdpd/sar.c                           |   22 +-
 usr.sbin/sdpd/scr.c                           |   11 +-
 usr.sbin/sdpd/sd.c                            |   63 +-
 usr.sbin/sdpd/sdpd.8                          |   45 +-
 usr.sbin/sdpd/server.c                        |  201 +-
 usr.sbin/sdpd/server.h                        |   44 +-
 usr.sbin/sdpd/sp.c                            |   23 +-
 usr.sbin/sdpd/srr.c                           |   14 +-
 usr.sbin/sdpd/ssar.c                          |  147 +-
 usr.sbin/sdpd/ssr.c                           |  235 +-
 usr.sbin/sdpd/sur.c                           |    9 +-
 usr.sbin/sdpd/uuid-private.h                  |    8 +-
 usr.sbin/sdpd/uuid.c                          |    8 +-
 227 files changed, 25064 insertions(+), 21687 deletions(-)
 create mode 100644 etc/bluetooth/hcsecd.conf
 create mode 100644 etc/defaults/bluetooth.device.conf
 create mode 100644 etc/rc.d/bluetooth
 delete mode 100644 etc/rc.d/btconfig
 delete mode 100644 etc/rc.d/bthcid
 create mode 100644 etc/rc.d/bthidd
 create mode 100644 etc/rc.d/hcsecd
 create mode 100644 etc/rc.d/ubthidhci
 create mode 100644 lib/libbluetooth/dev.c
 delete mode 100644 lib/libbluetooth/devaddr.c
 create mode 100644 lib/libbluetooth/hci.c
 delete mode 100644 share/man/man4/bluetooth.4
 create mode 100644 share/man/man4/ng_bluetooth.4
 create mode 100644 share/man/man4/ng_bt3c.4
 create mode 100644 share/man/man4/ng_btsocket.4
 create mode 100644 share/man/man4/ng_h4.4
 create mode 100644 share/man/man4/ng_hci.4
 create mode 100644 share/man/man4/ng_l2cap.4
 create mode 100644 share/man/man4/ng_ubt.4
 delete mode 100644 share/man/man4/ubt.4
 create mode 100644 share/man/man4/ubtbcmfw.4
 create mode 100644 share/man/man5/bluetooth.device.conf.5
 create mode 100644 share/man/man5/bluetooth.hosts.5
 create mode 100644 share/man/man5/bluetooth.protocols.5
 delete mode 100644 sys/netbt/Makefile
 delete mode 100644 sys/netbt/bluetooth.h
 delete mode 100644 sys/netbt/bt_input.c
 delete mode 100644 sys/netbt/bt_proto.c
 delete mode 100644 sys/netbt/hci.h
 delete mode 100644 sys/netbt/hci_event.c
 delete mode 100644 sys/netbt/hci_ioctl.c
 delete mode 100644 sys/netbt/hci_link.c
 delete mode 100644 sys/netbt/hci_misc.c
 delete mode 100644 sys/netbt/hci_socket.c
 delete mode 100644 sys/netbt/hci_unit.c
 delete mode 100644 sys/netbt/l2cap.h
 delete mode 100644 sys/netbt/l2cap_lower.c
 delete mode 100644 sys/netbt/l2cap_misc.c
 delete mode 100644 sys/netbt/l2cap_signal.c
 delete mode 100644 sys/netbt/l2cap_socket.c
 delete mode 100644 sys/netbt/l2cap_upper.c
 delete mode 100644 sys/netbt/rfcomm.h
 delete mode 100644 sys/netbt/rfcomm_dlc.c
 delete mode 100644 sys/netbt/rfcomm_session.c
 delete mode 100644 sys/netbt/rfcomm_socket.c
 delete mode 100644 sys/netbt/rfcomm_upper.c
 delete mode 100644 sys/netbt/sco.h
 delete mode 100644 sys/netbt/sco_socket.c
 delete mode 100644 sys/netbt/sco_upper.c
 create mode 100644 usr.bin/bthost/Makefile
 create mode 100644 usr.bin/bthost/bthost.1
 create mode 100644 usr.bin/bthost/bthost.c
 delete mode 100644 usr.bin/btpin/Makefile
 delete mode 100644 usr.bin/btpin/btpin.1
 delete mode 100644 usr.bin/btpin/btpin.c
 create mode 100644 usr.bin/btsockstat/Makefile
 create mode 100644 usr.bin/btsockstat/btsockstat.1
 create mode 100644 usr.bin/btsockstat/btsockstat.c
 delete mode 100644 usr.bin/rfcomm_sppd/rfcomm_sdp.h
 delete mode 100644 usr.bin/sdpquery/Makefile
 delete mode 100644 usr.bin/sdpquery/sdpquery.1
 delete mode 100644 usr.bin/sdpquery/sdpquery.c
 delete mode 100644 usr.bin/sdpquery/sdpquery.h
 create mode 100644 usr.sbin/ath3kfw/Makefile
 create mode 100644 usr.sbin/ath3kfw/ath3kfw.8
 create mode 100644 usr.sbin/ath3kfw/ath3kfw.c
 create mode 100644 usr.sbin/bcmfw/BCM-LEGAL.txt
 create mode 100644 usr.sbin/bcmfw/Makefile
 create mode 100644 usr.sbin/bcmfw/README
 create mode 100644 usr.sbin/bcmfw/bcmfw.8
 create mode 100644 usr.sbin/bcmfw/bcmfw.c
 create mode 100644 usr.sbin/bt3cfw/Makefile
 create mode 100644 usr.sbin/bt3cfw/bt3cfw.8
 create mode 100644 usr.sbin/bt3cfw/bt3cfw.c
 delete mode 100644 usr.sbin/btconfig/Makefile
 delete mode 100644 usr.sbin/btconfig/btconfig.8
 delete mode 100644 usr.sbin/btconfig/btconfig.c
 delete mode 100644 usr.sbin/bthcid/Makefile
 delete mode 100644 usr.sbin/bthcid/bthcid.8
 delete mode 100644 usr.sbin/bthcid/bthcid.c
 delete mode 100644 usr.sbin/bthcid/bthcid.h
 delete mode 100644 usr.sbin/bthcid/client.c
 delete mode 100644 usr.sbin/bthcid/config.c
 delete mode 100644 usr.sbin/bthcid/hci.c
 create mode 100644 usr.sbin/bthidcontrol/Makefile
 create mode 100644 usr.sbin/bthidcontrol/bthidcontrol.8
 create mode 100644 usr.sbin/bthidcontrol/bthidcontrol.c
 create mode 100644 usr.sbin/bthidcontrol/bthidcontrol.h
 create mode 100644 usr.sbin/bthidcontrol/hid.c
 create mode 100644 usr.sbin/bthidcontrol/sdp.c
 create mode 100644 usr.sbin/bthidd/Makefile
 create mode 100644 usr.sbin/bthidd/bthid_config.h
 create mode 100644 usr.sbin/bthidd/bthidd.8
 create mode 100644 usr.sbin/bthidd/bthidd.c
 create mode 100644 usr.sbin/bthidd/bthidd.conf.sample
 create mode 100644 usr.sbin/bthidd/bthidd.h
 create mode 100644 usr.sbin/bthidd/client.c
 create mode 100644 usr.sbin/bthidd/hid.c
 create mode 100644 usr.sbin/bthidd/kbd.c
 create mode 100644 usr.sbin/bthidd/kbd.h
 create mode 100644 usr.sbin/bthidd/lexer.l
 create mode 100644 usr.sbin/bthidd/parser.y
 create mode 100644 usr.sbin/bthidd/server.c
 create mode 100644 usr.sbin/bthidd/session.c
 create mode 100644 usr.sbin/btpand/Makefile
 create mode 100644 usr.sbin/btpand/bnep.c
 create mode 100644 usr.sbin/btpand/bnep.h
 create mode 100644 usr.sbin/btpand/btpand.8
 create mode 100644 usr.sbin/btpand/btpand.c
 create mode 100644 usr.sbin/btpand/btpand.h
 create mode 100644 usr.sbin/btpand/channel.c
 create mode 100644 usr.sbin/btpand/client.c
 create mode 100644 usr.sbin/btpand/event.c
 create mode 100644 usr.sbin/btpand/event.h
 create mode 100644 usr.sbin/btpand/packet.c
 create mode 100644 usr.sbin/btpand/sdp.c
 create mode 100644 usr.sbin/btpand/sdp.h
 create mode 100644 usr.sbin/btpand/server.c
 create mode 100644 usr.sbin/btpand/tap.c
 create mode 100644 usr.sbin/hccontrol/Makefile
 create mode 100644 usr.sbin/hccontrol/hccontrol.8
 create mode 100644 usr.sbin/hccontrol/hccontrol.c
 create mode 100644 usr.sbin/hccontrol/hccontrol.h
 create mode 100644 usr.sbin/hccontrol/host_controller_baseband.c
 create mode 100644 usr.sbin/hccontrol/info.c
 create mode 100644 usr.sbin/hccontrol/link_control.c
 create mode 100644 usr.sbin/hccontrol/link_policy.c
 create mode 100644 usr.sbin/hccontrol/node.c
 create mode 100644 usr.sbin/hccontrol/send_recv.c
 create mode 100644 usr.sbin/hccontrol/status.c
 create mode 100644 usr.sbin/hccontrol/util.c
 create mode 100644 usr.sbin/hcsecd/Makefile
 create mode 100644 usr.sbin/hcsecd/hcsecd.8
 create mode 100644 usr.sbin/hcsecd/hcsecd.c
 rename etc/bluetooth/bthcid.conf => usr.sbin/hcsecd/hcsecd.conf (63%)
 rename usr.sbin/{bthcid/bthcid.conf.5 => hcsecd/hcsecd.conf.5} (95%)
 create mode 100644 usr.sbin/hcsecd/hcsecd.h
 rename usr.sbin/{bthcid => hcsecd}/lexer.l (94%)
 rename usr.sbin/{bthcid => hcsecd}/parser.y (71%)
 create mode 100644 usr.sbin/hcseriald/Makefile
 create mode 100644 usr.sbin/hcseriald/hcseriald.8
 create mode 100644 usr.sbin/hcseriald/hcseriald.c
 create mode 100644 usr.sbin/l2control/Makefile
 create mode 100644 usr.sbin/l2control/l2cap.c
 create mode 100644 usr.sbin/l2control/l2control.8
 create mode 100644 usr.sbin/l2control/l2control.c
 create mode 100644 usr.sbin/l2control/l2control.h
 create mode 100644 usr.sbin/l2ping/Makefile
 create mode 100644 usr.sbin/l2ping/l2ping.8
 create mode 100644 usr.sbin/l2ping/l2ping.c
 create mode 100644 usr.sbin/rfcomm_pppd/Makefile
 create mode 100644 usr.sbin/rfcomm_pppd/rfcomm_pppd.8
 create mode 100644 usr.sbin/rfcomm_pppd/rfcomm_pppd.c
 create mode 100644 usr.sbin/sdpcontrol/Makefile
 create mode 100644 usr.sbin/sdpcontrol/sdpcontrol.8
 create mode 100644 usr.sbin/sdpcontrol/sdpcontrol.c
 create mode 100644 usr.sbin/sdpcontrol/sdpcontrol.h
 rename {usr.bin/sdpquery => usr.sbin/sdpcontrol}/search.c (77%)
 create mode 100644 usr.sbin/sdpd/gn.c
 delete mode 100644 usr.sbin/sdpd/hf.c
 delete mode 100644 usr.sbin/sdpd/hset.c
 create mode 100644 usr.sbin/sdpd/nap.c
 create mode 100644 usr.sbin/sdpd/panu.c

diff --git a/Makefile_upgrade.inc b/Makefile_upgrade.inc
index b1342bac73..0240b78f01 100644
--- a/Makefile_upgrade.inc
+++ b/Makefile_upgrade.inc
@@ -3916,6 +3916,22 @@ TO_REMOVE+=/usr/libexec/dhcpcd-hooks/02-dump
 TO_REMOVE+=/usr/lib/libtcplay.so.2
 TO_REMOVE+=/usr/include/pcap/export-defs.h
 TO_REMOVE+=/usr/share/mk/bsd.patch.mk
+TO_REMOVE+=/boot/kernel/netbt.ko
+TO_REMOVE+=/boot/kernel/ubt.ko
+TO_REMOVE+=/etc/bluetooth/bthcid.conf
+TO_REMOVE+=/etc/rc.d/btconfig
+TO_REMOVE+=/etc/rc.d/bthcid
+TO_REMOVE+=/usr/bin/btpin
+TO_REMOVE+=/usr/bin/sdpquery
+TO_REMOVE+=/usr/include/netbt
+TO_REMOVE+=/usr/sbin/btconfig
+TO_REMOVE+=/usr/sbin/bthcid
+TO_REMOVE+=/usr/share/man/man1/btpin.1.gz
+TO_REMOVE+=/usr/share/man/man1/sdpquery.1.gz
+TO_REMOVE+=/usr/share/man/man4/bluetooth.4.gz
+TO_REMOVE+=/usr/share/man/man4/ubt.4.gz
+TO_REMOVE+=/usr/share/man/man8/btconfig.8.gz
+TO_REMOVE+=/usr/share/man/man8/bthcid.8.gz
 
 .if !defined(WANT_INSTALLER)
 TO_REMOVE+=/usr/sbin/dfuibe_installer
diff --git a/etc/Makefile b/etc/Makefile
index 1140b61267..d9dfa227de 100644
--- a/etc/Makefile
+++ b/etc/Makefile
@@ -42,8 +42,8 @@ DIRS+=	lib/libssh usr.bin/openssl usr.bin/ssh usr.sbin/sshd
 #
 BIN2=	pccard_ether rc.suspend rc.resume
 
-DEFAULTS= compilers.conf devfs.conf make.conf periodic.conf \
-	  pfi.conf rc.conf uuids
+DEFAULTS= bluetooth.device.conf compilers.conf devfs.conf make.conf \
+	  periodic.conf pfi.conf rc.conf uuids
 
 MTREE=	BSD.include.dist BSD.root.dist BSD.usr.dist BSD.var.dist
 .if !defined(NOFSCHG)
diff --git a/etc/bluetooth/Makefile b/etc/bluetooth/Makefile
index d07efd58ab..1bd86841a3 100644
--- a/etc/bluetooth/Makefile
+++ b/etc/bluetooth/Makefile
@@ -1,16 +1,9 @@
-# $DragonFly: src/etc/bluetooth/Makefile,v 1.2 2008/02/12 21:36:19 hasso Exp $
+# $Id: Makefile,v 1.2 2003/10/21 22:22:27 max Exp $
+# $FreeBSD: head/etc/bluetooth/Makefile 151325 2005-10-14 15:26:23Z ru $
 
 FILESDIR=		/etc/bluetooth
-FILES=			protocols
-
-.if !exists(${DESTDIR}/etc/bluetooth/hosts)
-FILES+=			hosts
+FILES=			hcsecd.conf hosts protocols
+FILESMODE_hcsecd.conf=	600
 FILESMODE_hosts=	644
-.endif
-
-.if !exists(${DESTDIR}/etc/bluetooth/bthcid.conf)
-FILES+=			bthcid.conf
-FILESMODE_bthcid.conf=	600
-.endif
 
 .include <bsd.prog.mk>
diff --git a/etc/bluetooth/hcsecd.conf b/etc/bluetooth/hcsecd.conf
new file mode 100644
index 0000000000..6821d86540
--- /dev/null
+++ b/etc/bluetooth/hcsecd.conf
@@ -0,0 +1,56 @@
+# $Id: hcsecd.conf,v 1.1 2003/05/26 22:50:47 max Exp $
+# $FreeBSD: head/etc/bluetooth/hcsecd.conf 158726 2006-05-18 17:53:49Z emax $
+#
+# HCI security daemon configuration file
+#
+# Format:
+#
+# device {
+#	option	value ;
+# }
+#
+# Possible options and values
+#
+# Options	Values
+# ----------------------------------
+# bdaddr	xx:xx:xx:xx:xx:xx ;  	- remote device BD_ADDR
+# name 		"any char" ;		- to set user friendly device name
+# key		0x11223344 | nokey ;	- to set link key for the device
+# pin		"secret" | nopin ;	- to PIN code for the device
+#
+# Notes:
+#
+#	Currently there is no way to select keys/PIN code based on which
+#	local device received the request. Everything is based on remote
+#	device BD_ADDR.
+#
+#	"nokey"	means that no link key has been defined and we should
+#		send Link_Key_Negative_Reply command to the device.
+#
+#	"nopin"	means that no PIN code has been defined and we should
+#		send PIN_Code_Negative_Reply command to the device
+#
+
+# Default entry is applied if no better match found
+# It MUST have 00:00:00:00:00:00 as bdaddr
+device {
+	bdaddr	00:00:00:00:00:00;
+	name	"Default entry";
+	key	nokey;
+	pin	nopin;
+}
+
+device {
+	bdaddr	00:01:02:03:04:05;
+	name	"Dummy";
+	key	nokey;
+	pin	"0000";
+}
+
+device {
+	bdaddr	00:11:22:33:44:55;
+	name	"Dummy";
+	key	0x00112233445566778899aabbccddeeff; # 16 bytes key (hex string)
+	pin	nopin;
+}
+
diff --git a/etc/bluetooth/hosts b/etc/bluetooth/hosts
index 7ddfc5df0d..0c45efc86e 100644
--- a/etc/bluetooth/hosts
+++ b/etc/bluetooth/hosts
@@ -1,7 +1,5 @@
-# $DragonFly: src/etc/bluetooth/hosts,v 1.1 2008/01/03 13:35:20 hasso Exp $
-# $NetBSD: hosts,v 1.1 2006/06/19 15:44:35 gdamore Exp $
-# $Id: hosts,v 1.1 2006/06/19 15:44:35 gdamore Exp $
-# $FreeBSD: /repoman/r/ncvs/src/etc/bluetooth/hosts,v 1.2 2005/11/10 19:09:22 emax Exp $
+# $Id: hosts,v 1.1 2003/05/21 17:48:40 max Exp $
+# $FreeBSD: head/etc/bluetooth/hosts 152286 2005-11-10 19:09:22Z emax $
 #
 # Bluetooth Host Database
 #
diff --git a/etc/bluetooth/protocols b/etc/bluetooth/protocols
index 396b55014d..99029b2374 100644
--- a/etc/bluetooth/protocols
+++ b/etc/bluetooth/protocols
@@ -1,7 +1,5 @@
-# $DragonFly: src/etc/bluetooth/protocols,v 1.1 2008/01/03 13:35:20 hasso Exp $
-# $NetBSD: protocols,v 1.1 2006/06/19 15:44:35 gdamore Exp $
-# $Id: protocols,v 1.1 2006/06/19 15:44:35 gdamore Exp $
-# $FreeBSD: /repoman/r/ncvs/src/etc/bluetooth/protocols,v 1.2 2005/11/10 19:09:22 emax Exp $
+# $Id: protocols,v 1.2 2003/05/21 22:17:14 max Exp $
+# $FreeBSD: head/etc/bluetooth/protocols 152286 2005-11-10 19:09:22Z emax $
 #
 # Bluetooth Protocol/Service Multiplexor (PSM) names and numbers
 #
@@ -21,3 +19,4 @@ upnp             21  UPnP          # See ESDP, Bluetooth SIG
 avctp            23  AVCTP         # Audio/Video Control Transport Protocol
 avdtp            25  AVDTP         # Audio/Video Distribution Transport Protocol
 udi-c-plane      29  UDI-C-Plane   # Unrestricted Digital Information Profile
+
diff --git a/etc/defaults/bluetooth.device.conf b/etc/defaults/bluetooth.device.conf
new file mode 100644
index 0000000000..9d91d45352
--- /dev/null
+++ b/etc/defaults/bluetooth.device.conf
@@ -0,0 +1,111 @@
+# Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+# 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: head/etc/defaults/bluetooth.device.conf 179360 2008-05-27 17:46:32Z emax $
+
+# The authentication_enable parameter controls if the device requires to
+# authenticate the remote device at connection setup. At connection setup,
+# only the devices with the authentication_enable parameter enabled will
+# try to authenticate the other device.
+#
+# Possible values:
+#
+# NO  or 0	authentication disabled (default);
+# YES or 1	authentication enabled.
+
+# authentication_enable="NO"
+
+# The class parameter is used to indicate the capabilities of the device to
+# other devices.
+#
+# For more details see "Assigned Numbers - Bluetooth Baseband" document
+#
+# Possible value:
+#
+# xx:xx:xx	where xx is a hex number
+
+# class="ff:01:0c"
+
+# The connectable parameter controls whether or not the device should
+# periodically scan for page attempts from other devices.
+#
+# Possible values:
+#
+# NO  or 0	do not scan for page attempts;
+# YES or 1	scan for page attempts (default).
+
+# connectable="YES"
+
+# The discoverable parameter controls whether or not the device should
+# periodically scan for inquiry requests from other devices.
+#
+# Possible values:
+#
+# NO  or 0	do not scan for inquiry requests;
+# YES or 1	scan for inquiry requests (default).
+
+# discoverable="YES"
+
+# The encryption_mode parameter controls if the device requires encryption
+# to the remote device at connection setup. At connection setup, only the
+# devices with the authentication_enable parameter enabled and encryption_mode
+# parameter enabled will try to encrypt the connection to the other device.
+#
+# Possible values:
+#
+# NONE or 0	encryption disabled (default);
+# P2P  or 1	encryption only for point-to-point packets;
+# ALL  or 2	encryption for both point-to-point and broadcast packets.
+
+# encryption_mode="NONE"
+
+# HCI node debug level. Higher values mean more verbose output.
+#
+# Possible values: 0 - 4
+
+# hci_debug_level="3"
+
+# L2CAP node debug level. Higher values mean more verbose output.
+#
+# Possible values: 0 - 4
+
+# l2cap_debug_level="3"
+
+# The local_name parameter provides the ability to modify the user friendly
+# name for the device.
+
+# local_name="My device"
+
+# The role_switch parameter controls whether the local device should perform
+# role switch. By default, if role switch is supported, the local device will
+# try to perform role switch and become Master on incoming connection. Some
+# devices do not support role switch and thus incoming connections from such
+# devices will fail. If role switch is disabled then accepting device will
+# remain Slave.
+#
+# NO  or 0	do not perform role switch;
+# YES or 1	perform role switch (default).
+
+# role_switch="YES"
+
diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf
index b745c40adf..8968922605 100644
--- a/etc/defaults/rc.conf
+++ b/etc/defaults/rc.conf
@@ -198,15 +198,36 @@ dntpd_enable="NO"		# Run dntpd Network Time Protocol (or NO).
 dntpd_program="/usr/sbin/dntpd"	# path to dntpd, if you want a different one.
 dntpd_flags=""			# Flags to dntpd (if enabled) also server name(s)
 
-# Bluetooth deamons and options:
-btconfig_enable="NO"		# Configure Bluetooth devices (or NO).
-btconfig_devices=""		# List of Bluetooth devices (or empty for all).
-#btconfig_<device>=""		# Parameters to pass to <device>.
-btconfig_args=""		# Parameters to pass to all devices.
-sdpd_enable="NO"		# Run the Service Discovery Profile daemon (or NO).
-sdpd_flags=""			# Flags to sdpd (if enabled).
-bthcid_enable="NO"		# Run the Bluetooth Link Key/PIN Code Manager (or NO).
-bthcid_flags=""			# Flags to bthcid (if enabled).
+### Bluetooth ###
+hcsecd_enable="NO"		# Enable hcsecd(8) (or NO)
+hcsecd_config="/etc/bluetooth/hcsecd.conf" # hcsecd(8) configuration file
+
+sdpd_enable="NO"		# Enable sdpd(8) (or NO)
+sdpd_control="/var/run/sdp"	# sdpd(8) control socket
+sdpd_groupname="nobody"		# set spdp(8) user/group to run as after
+sdpd_username="nobody"		# it initializes
+
+bthidd_enable="NO"		# Enable bthidd(8) (or NO)
+bthidd_config="/etc/bluetooth/bthidd.conf" # bthidd(8) configuration file
+bthidd_hids="/var/db/bthidd.hids" # bthidd(8) known HID devices file
+
+rfcomm_pppd_server_enable="NO"	# Enable rfcomm_pppd(8) in server mode (or NO)
+rfcomm_pppd_server_profile="one two"	# Profile to use from /etc/ppp/ppp.conf
+#
+#rfcomm_pppd_server_one_bdaddr=""	# Override local bdaddr for 'one'
+rfcomm_pppd_server_one_channel="1"	# Override local channel for 'one'
+#rfcomm_pppd_server_one_register_sp="NO"	# Override SP and DUN register
+#rfcomm_pppd_server_one_register_dun="NO"	# for 'one'
+#
+#rfcomm_pppd_server_two_bdaddr=""	# Override local bdaddr for 'two'
+rfcomm_pppd_server_two_channel="3"	# Override local channel for 'two'
+#rfcomm_pppd_server_two_register_sp="NO"	# Override SP and DUN register
+#rfcomm_pppd_server_two_register_dun="NO"	# for 'two'
+
+ubthidhci_enable="NO"		# Switch an USB BT controller present on
+#ubthidhci_busnum="3"		# bus 3 and addr 2 from HID mode to HCI mode.
+#ubthidhci_addr="2"		# Check usbconfig list to find the correct
+				# numbers for your system.
 
 # Network Information Services (NIS) options: All need rpcbind_enable="YES" ###
 nis_client_enable="NO"		# We're an NIS client (or NO).
diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist
index 38535da037..c28448c8a0 100644
--- a/etc/mtree/BSD.include.dist
+++ b/etc/mtree/BSD.include.dist
@@ -285,8 +285,6 @@
         vlan
         ..
     ..
-    netbt
-    ..
     netgraph
         UI
         ..
@@ -346,6 +344,10 @@
         ..
         async
         ..
+        bluetooth
+            include
+            ..
+        ..
         bpf
         ..
         bridge
diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile
index fae9156a18..ac03b8a4ba 100644
--- a/etc/rc.d/Makefile
+++ b/etc/rc.d/Makefile
@@ -7,12 +7,11 @@
 #
 FILES=	DAEMON LOGIN NETWORKING SERVERS \
 	accounting addswap adjkerntz automount automountd autounmountd \
-	bootconf bootparams btconfig bthcid ccd cleanvar cryptdisks \
-	cleartmp cron cryptdisks \
-	devd devfs dhclient dhcp_client dhcpcd diskless dmesg dntpd dumpon \
-	fixbootfile fsck ftpd hostname hotplugd \
-	inetd initdiskless initrandom ip6addrctl ip6fw ipfw ipfw3 \
-	jail keyserv \
+	bluetooth bootconf bootparams bthidd \
+	ccd cleanvar cryptdisks cleartmp cron cryptdisks \
+	devd devfs dhclient dhcp_client dhcpcd diskless dmesg dumpon \
+	fixbootfile fsck ftpd hcsecd hostname hotplugd \
+	inetd initdiskless initrandom ip6fw ipfw ipfw3 jail keyserv \
 	ldconfig local localdaemons lockd lpd lvm \
 	mixer modules motd mountcritlocal mountcritremote mountd mounttmpfs \
 	moused msgs \
@@ -23,7 +22,7 @@ FILES=	DAEMON LOGIN NETWORKING SERVERS \
 	routing rpcbind rtadvd rtsold rwho sysdb savecore sdpd securelevel \
 	sendmail sensorsd serial sppp sshd statd swap1 syscons \
 	sysctl syslogd sysvipcd \
-	ttys udevd udevd_early \
+	ttys ubthidhci udevd udevd_early \
 	varsym vfs_quota vinum virecover vkernel vknetd \
 	watchdogd wpa_supplicant \
 	ypbind yppasswdd ypserv ypset ypupdated ypxfrd
diff --git a/etc/rc.d/bluetooth b/etc/rc.d/bluetooth
new file mode 100644
index 0000000000..e4a57cb4f3
--- /dev/null
+++ b/etc/rc.d/bluetooth
@@ -0,0 +1,365 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+# 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: head/etc/rc.d/bluetooth 208060 2010-05-14 04:53:57Z dougb $
+
+# PROVIDE: bluetooth
+# REQUIRE: DAEMON
+# KEYWORD: nojail nostart
+
+. /etc/rc.subr
+
+name="bluetooth"
+rcvar=
+start_cmd="bluetooth_start"
+stop_cmd="bluetooth_stop"
+required_modules="ng_bluetooth ng_hci ng_l2cap ng_btsocket"
+
+##############################################################################
+# Read and parse Bluetooth device configuration file
+##############################################################################
+
+bluetooth_read_conf()
+{
+	local _err _file _line _namespace
+
+	_file=$1
+	_namespace=$2
+	_err=0
+
+	if [ ! -e $_file ]; then
+		return 0
+	fi
+
+	if [ ! -f $_file -o ! -r $_file ]; then
+		err 1 "Bluetooth configuration file $_file is not a file or not readable"
+	fi
+
+	while read _line
+	do
+		case "$_line" in
+		\#*)
+			continue
+			;;
+
+		*)
+			if [ -z "$_line" ]; then
+				continue;
+			fi
+
+
+			if expr "$_line" : "[a-zA-Z0-9_]*=" > /dev/null 2>&1; then
+				eval "${_namespace}${_line}"
+			else
+				warn "Unable to parse line \"$_line\" in $_file"
+				_err=1
+			fi
+			;;
+		esac
+	done < $_file
+
+	return $_err
+}
+
+##############################################################################
+# Setup Bluetooth stack. Create and connect nodes
+##############################################################################
+
+bluetooth_setup_stack()
+{
+	dev=$1
+	shift
+	hook=$1
+	shift
+
+	# Setup HCI
+	ngctl mkpeer ${dev}: hci ${hook} drv \
+		> /dev/null 2>&1 || return 1
+
+	ngctl name ${dev}:${hook} ${dev}hci \
+		> /dev/null 2>&1 || return 1
+
+	ngctl msg ${dev}hci: set_debug ${bluetooth_device_hci_debug_level} \
+		> /dev/null 2>&1 || return 1
+
+	# Setup L2CAP
+	ngctl mkpeer ${dev}hci: l2cap acl hci \
+		> /dev/null 2>&1 || return 1
+
+	ngctl name ${dev}hci:acl ${dev}l2cap \
+		> /dev/null 2>&1 || return 1
+
+	ngctl msg ${dev}l2cap: set_debug ${bluetooth_device_l2cap_debug_level} \
+		> /dev/null 2>&1 || return 1
+
+	# Connect HCI node to the Bluetooth sockets layer
+	ngctl connect ${dev}hci: btsock_hci_raw: raw ${dev}raw \
+		> /dev/null 2>&1 || return 1
+
+	# Connect L2CAP node to Bluetooth sockets layer
+	ngctl connect ${dev}l2cap: btsock_l2c_raw: ctl ${dev}ctl \
+		> /dev/null 2>&1 || return 1
+
+	ngctl connect ${dev}l2cap: btsock_l2c: l2c ${dev}l2c \
+		> /dev/null 2>&1 || return 1
+
+	# Initialize HCI node
+	${hccontrol} -n ${dev}hci reset \
+		> /dev/null 2>&1 || return 1
+
+	${hccontrol} -n ${dev}hci read_bd_addr \
+		> /dev/null 2>&1 || return 1
+
+	${hccontrol} -n ${dev}hci read_local_supported_features \
+		> /dev/null 2>&1 || return 1
+
+	${hccontrol} -n ${dev}hci read_buffer_size \
+		> /dev/null 2>&1 || return 1
+
+	if checkyesno bluetooth_device_discoverable; then
+		if checkyesno bluetooth_device_connectable; then
+			${hccontrol} -n ${dev}hci write_scan_enable 3 \
+				> /dev/null 2>&1 || return 1
+		else
+			${hccontrol} -n ${dev}hci write_scan_enable 1 \
+				> /dev/null 2>&1 || return 1
+		fi
+	else
+		if checkyesno bluetooth_device_connectable; then
+			${hccontrol} -n ${dev}hci write_scan_enable 2 \
+				> /dev/null 2>&1 || return 1
+		else
+			${hccontrol} -n ${dev}hci write_scan_enable 0 \
+				> /dev/null 2>&1 || return 1
+		fi
+	fi
+
+
+	${hccontrol} -n ${dev}hci write_class_of_device ${bluetooth_device_class} \
+		> /dev/null 2>&1 || return 1
+
+	if checkyesno bluetooth_device_authentication_enable; then
+		${hccontrol} -n ${dev}hci write_authentication_enable 1 \
+			> /dev/null 2>&1 || return 1
+	else
+		${hccontrol} -n ${dev}hci write_authentication_enable 0 \
+			> /dev/null 2>&1 || return 1
+	fi
+
+	case "${bluetooth_device_encryption_mode}" in
+	[Nn][Oo][Nn][Ee]|0)
+		${hccontrol} -n ${dev}hci write_encryption_mode 0 \
+			> /dev/null 2>&1 || return 1
+		;;
+
+	[Pp][2][Pp]|1)
+		${hccontrol} -n ${dev}hci write_encryption_mode 1 \
+			> /dev/null 2>&1 || return 1
+		;;
+
+	[Al][Ll][Ll]|2)
+		${hccontrol} -n ${dev}hci write_encryption_mode 2 \
+			> /dev/null 2>&1 || return 1
+		;;
+
+	*)
+		warn "Unsupported encryption mode ${bluetooth_device_encryption_mode} for device ${dev}"
+		return 1
+		;;
+	esac
+
+	if checkyesno bluetooth_device_role_switch; then
+		${hccontrol} -n ${dev}hci write_node_role_switch 1 \
+			> /dev/null 2>&1 || return 1
+	else
+		${hccontrol} -n ${dev}hci write_node_role_switch 0 \
+			> /dev/null 2>&1 || return 1
+	fi
+
+	${hccontrol} -n ${dev}hci change_local_name "${bluetooth_device_local_name}" \
+		> /dev/null 2>&1 || return 1
+
+	${hccontrol} -n ${dev}hci initialize \
+		> /dev/null 2>&1 || return 1
+
+	return 0
+}
+
+##############################################################################
+# Shutdown Bluetooth stack. Destroy all nodes
+##############################################################################
+
+bluetooth_shutdown_stack()
+{
+	dev=$1
+
+	ngctl shutdown ${dev}hci: > /dev/null 2>&1
+	ngctl shutdown ${dev}l2cap: > /dev/null 2>&1
+
+	return 0
+}
+
+##############################################################################
+# bluetooth_start()
+##############################################################################
+
+bluetooth_start()
+{
+	local _file
+
+	dev=$1
+
+	# Try to figure out device type by looking at device name
+	case "${dev}" in
+	# uartX - serial/UART Bluetooth device
+	uart*)
+		load_kld ng_h4 || return 1
+
+		hook="hook"
+
+		# Obtain unit number from device.
+		unit=`expr ${dev} : 'uart\([0-9]\{1,\}\)'`
+		if [ -z "${unit}" ]; then
+			err 1 "Unable to get uart unit number: ${dev}"
+		fi
+
+		${hcseriald} -f /dev/cuau${unit} -n ${dev}
+		sleep 1 # wait a little bit
+
+		if [ ! -f "/var/run/hcseriald.${dev}.pid" ]; then
+			err 1 "Unable to start hcseriald on ${dev}"
+		fi
+		;;
+
+	# 3Com Bluetooth Adapter 3CRWB60-A
+	btccc*)
+		hook="hook"
+
+		# Obtain unit number from device.
+		unit=`expr ${dev} : 'btccc\([0-9]\{1,\}\)'`
+		if [ -z "${unit}" ]; then
+			err 1 "Unable to get bt3c unit number: ${dev}"
+		fi
+		;;
+
+	# USB Bluetooth adapters
+	ubt*)
+		hook="hook"
+
+		# Obtain unit number from device.
+		unit=`expr ${dev} : 'ubt\([0-9]\{1,\}\)'`
+		if [ -z "${unit}" ]; then
+			err 1 "Unable to get ubt unit number: ${dev}"
+		fi
+		;;
+
+	# Unknown
+	*)
+		err 1 "Unsupported device: ${dev}"
+		;;
+	esac
+
+	# Be backward compatible and setup reasonable defaults
+	bluetooth_device_authentication_enable="0"
+	bluetooth_device_class="ff:01:0c"
+	bluetooth_device_connectable="1"
+	bluetooth_device_discoverable="1"
+	bluetooth_device_encryption_mode="0"
+	bluetooth_device_hci_debug_level="3"
+	bluetooth_device_l2cap_debug_level="3"
+	bluetooth_device_local_name="`/usr/bin/uname -n` (${dev})"
+	bluetooth_device_role_switch="1"
+
+	# Load default device configuration parameters
+	_file="/etc/defaults/bluetooth.device.conf"
+
+	if ! bluetooth_read_conf $_file bluetooth_device_ ; then
+		err 1 "Unable to read default Bluetooth configuration from $_file"
+	fi
+
+	# Load device specific overrides
+	_file="/etc/bluetooth/$dev.conf"
+
+	if ! bluetooth_read_conf $_file bluetooth_device_ ; then
+		err 1 "Unable to read Bluetooth device configuration from $_file"
+	fi
+
+	# Setup stack
+	if ! bluetooth_setup_stack ${dev} ${hook} ; then
+		bluetooth_shutdown_stack $dev
+		err 1 "Unable to setup Bluetooth stack for device ${dev}"
+	fi
+
+	return 0
+}
+
+##############################################################################
+# bluetooth_stop()
+##############################################################################
+
+bluetooth_stop()
+{
+	dev=$1
+
+	# Try to figure out device type by looking at device name
+	case "${dev}" in
+	# uartX - serial/UART Bluetooth device
+	uart*)
+		if [ -f "/var/run/hcseriald.${dev}.pid" ]; then
+			kill `cat /var/run/hcseriald.${dev}.pid`
+			sleep 1 # wait a little bit
+		fi
+		;;
+
+	# 3Com Bluetooth Adapter 3CRWB60-A
+	btccc*)
+		;;
+
+	# USB Bluetooth adapters
+	ubt*)
+		;;
+
+	# Unknown
+	*)
+		err 1 "Unsupported device: ${dev}"
+		;;
+	esac
+
+	bluetooth_shutdown_stack ${dev}
+
+	return 0
+}
+
+##############################################################################
+# Start here
+##############################################################################
+
+load_rc_config $name
+hccontrol="${bluetooth_hccontrol:-/usr/sbin/hccontrol}"
+hcseriald="${bluetooth_hcseriald:-/usr/sbin/hcseriald}"
+
+run_rc_command $*
+
diff --git a/etc/rc.d/btconfig b/etc/rc.d/btconfig
deleted file mode 100644
index c5869f0595..0000000000
--- a/etc/rc.d/btconfig
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-#
-# $NetBSD: btconfig,v 1.1 2006/06/19 15:44:36 gdamore Exp $
-#
-
-# PROVIDE: bluetooth
-# REQUIRE: DAEMON
-# BEFORE:  LOGIN
-
-. /etc/rc.subr
-
-name="btconfig"
-rcvar=${name}
-command="/usr/sbin/${name}"
-start_cmd="btconfig_start"
-stop_cmd="btconfig_stop"
-status_cmd="btconfig_status"
-
-btconfig_start()
-{
-	echo -n 'Configuring Bluetooth controllers:'
-
-	#
-	# Configure Bluetooth controllers.
-	#
-	# If ${btconfig_devices} is set, it should be a list of devices to
-	# configure. Otherwise, all available devices will be configured.
-	#
-	# If ${btconfig_<dev>} is set, it will be used as the parameter
-	# list for btconfig. Otherwise ${btconfig_args} will be used or
-	# if that is not set, the default string "enable" will be used.
-	#
-
-	devs="${btconfig_devices:-$(${command} -l)}"
-	for dev in ${devs}; do
-		eval args="\$btconfig_${dev}"
-		if [ -z "${args}" ]; then
-			args="${btconfig_args:-enable}"
-		fi
-
-		echo -n " ${dev}"
-		${command} ${dev} ${args}
-	done
-
-	echo '.'
-}
-
-btconfig_stop()
-{
-	echo -n 'Disabling Bluetooth controllers:'
-
-	devs="${btconfig_devices:-$(${command} -l)}"
-	for dev in ${devs}; do
-		echo -n " ${dev}"
-		${command} ${dev} disable
-	done
-
-	echo '.'
-}
-
-btconfig_status()
-{
-	${command}
-}
-
-load_rc_config ${name}
-run_rc_command "$1"
diff --git a/etc/rc.d/bthcid b/etc/rc.d/bthcid
deleted file mode 100644
index 2459c2c3e6..0000000000
--- a/etc/rc.d/bthcid
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-#
-# $NetBSD: bthcid,v 1.1 2006/06/19 15:44:36 gdamore Exp $
-#
-
-# PROVIDE: bthcid
-# REQUIRE: bluetooth
-# BEFORE: LOGIN
-
-. /etc/rc.subr
-
-name="bthcid"
-rcvar=$name
-
-command="/usr/sbin/${name}"
-pidfile="/var/run/${name}.pid"
-
-load_rc_config $name
-run_rc_command "$1"
diff --git a/etc/rc.d/bthidd b/etc/rc.d/bthidd
new file mode 100644
index 0000000000..1a1a59fca8
--- /dev/null
+++ b/etc/rc.d/bthidd
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# $FreeBSD: head/etc/rc.d/bthidd 230099 2012-01-14 02:18:41Z dougb $
+#
+
+# PROVIDE: bthidd
+# REQUIRE: DAEMON hcsecd
+# BEFORE: LOGIN
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+name="bthidd"
+rcvar="bthidd_enable"
+command="/usr/sbin/${name}"
+pidfile="/var/run/${name}.pid"
+start_precmd="bthidd_prestart"
+
+bthidd_prestart()
+{
+	load_kld -m kbdmux kbdmux
+	load_kld -m vkbd vkbd
+	load_kld -m ng_btsocket ng_btsocket
+	return 0
+}
+
+load_rc_config $name
+config="${bthidd_config:-/etc/bluetooth/${name}.conf}"
+hids="${bthidd_hids:-/var/db/${name}.hids}"
+command_args="-c ${config} -H ${hids} -p ${pidfile}"
+required_files="${config}"
+
+run_rc_command "$1"
diff --git a/etc/rc.d/hcsecd b/etc/rc.d/hcsecd
new file mode 100644
index 0000000000..6bcba53c5d
--- /dev/null
+++ b/etc/rc.d/hcsecd
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# $FreeBSD: head/etc/rc.d/hcsecd 230099 2012-01-14 02:18:41Z dougb $
+#
+
+# PROVIDE: hcsecd
+# REQUIRE: DAEMON
+# BEFORE: LOGIN
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+name="hcsecd"
+rcvar="hcsecd_enable"
+command="/usr/sbin/${name}"
+pidfile="/var/run/${name}.pid"
+required_modules="ng_btsocket"
+
+load_rc_config $name
+config="${hcsecd_config:-/etc/bluetooth/${name}.conf}"
+command_args="-f ${config}"
+required_files="${config}"
+
+run_rc_command "$1"
diff --git a/etc/rc.d/sdpd b/etc/rc.d/sdpd
index 40d28a72f3..2d4ec7c72a 100644
--- a/etc/rc.d/sdpd
+++ b/etc/rc.d/sdpd
@@ -1,17 +1,24 @@
 #!/bin/sh
 #
-# $NetBSD: sdpd,v 1.2 2007/03/18 15:53:54 plunky Exp $
+# $FreeBSD: head/etc/rc.d/sdpd 230099 2012-01-14 02:18:41Z dougb $
 #
 
 # PROVIDE: sdpd
-# REQUIRE: bluetooth
+# REQUIRE: DAEMON
 # BEFORE: LOGIN
+# KEYWORD: nojail shutdown
 
 . /etc/rc.subr
 
 name="sdpd"
-rcvar=$name
 command="/usr/sbin/${name}"
+rcvar="sdpd_enable"
+required_modules="ng_btsocket"
 
 load_rc_config $name
+control="${sdpd_control:-/var/run/sdp}"
+group="${sdpd_groupname:-nobody}"
+user="${sdpd_username:-nobody}"
+command_args="-c ${control} -g ${group} -u ${user}"
+
 run_rc_command "$1"
diff --git a/etc/rc.d/ubthidhci b/etc/rc.d/ubthidhci
new file mode 100644
index 0000000000..b5782132d2
--- /dev/null
+++ b/etc/rc.d/ubthidhci
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# $FreeBSD: head/etc/rc.d/ubthidhci 230099 2012-01-14 02:18:41Z dougb $
+#
+
+# PROVIDE: ubthidhci
+# REQUIRE: DAEMON
+# BEFORE: bluetooth
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+name="ubthidhci"
+rcvar="ubthidhci_enable"
+command="/usr/sbin/usbconfig"
+start_precmd="ubthidhci_prestart"
+
+ubthidhci_prestart()
+{
+
+	if [ -z ${ubthidhci_busnum} ]; then
+		warn ubthidhci_busnum is not set
+		return 1
+	fi
+	if [ -z ${ubthidhci_addr} ]; then
+		warn ubthidhci_addr is not set
+		return 1
+	fi
+}
+
+load_rc_config $name
+#
+# We discard the output because:
+# 1) we don't want it to show up during boot; and
+# 2) the request usually returns an error, but that doesn't mean it failed
+#
+# NB: 0x40 is UT_VENDOR
+command_args="-u ${ubthidhci_busnum} -a ${ubthidhci_addr} do_request 0x40 0 0 0 0 > /dev/null 2>&1"
+
+run_rc_command "$1"
diff --git a/include/Makefile b/include/Makefile
index 0abb644089..44f47e93e9 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -43,7 +43,7 @@ LHDRS=	aio.h errno.h fcntl.h linker_set.h poll.h sched.h syslog.h ucontext.h
 # Other directories, like 'bus' and 'netproto', are created using mtree.
 #
 # XXX allow these directories to not contain header files.
-LDIRS=	net netbt netgraph netgraph7 netinet netinet6 sys vm
+LDIRS=	net netgraph netgraph7 netinet netinet6 sys vm
 
 # Subdirectories containing header files to copy.  In symlink mode
 # the subdirectory will be symlinked.  Care must be taken to adjust
@@ -76,7 +76,8 @@ LSUBDIRS= \
 	netgraph/mppc netgraph/one2many netgraph/ppp \
 	netgraph/pppoe netgraph/pptpgre netgraph/rfc1490 netgraph/socket \
 	netgraph/tee netgraph/tty netgraph/vjc \
-	netgraph7/UI netgraph7/async netgraph7/bpf \
+	netgraph7/UI netgraph7/async \
+	netgraph7/bluetooth/include netgraph7/bpf \
 	netgraph7/bridge netgraph7/cisco netgraph7/deflate netgraph7/echo \
 	netgraph7/eiface netgraph7/etf netgraph7/ether \
 	netgraph7/frame_relay netgraph7/hole netgraph7/hub \
diff --git a/lib/libbluetooth/Makefile b/lib/libbluetooth/Makefile
index 9538cc9865..a34fb531a2 100644
--- a/lib/libbluetooth/Makefile
+++ b/lib/libbluetooth/Makefile
@@ -1,16 +1,16 @@
-# $NetBSD: Makefile,v 1.3 2007/05/28 12:06:18 tls Exp $
-
-SYSDIR= ${.CURDIR}/../../sys/
+# $Id: Makefile,v 1.5 2003/07/22 18:38:04 max Exp $
+# $FreeBSD: head/lib/libbluetooth/Makefile 195767 2009-07-19 17:25:24Z kensmith $
 
 LIB=		bluetooth
-SHLIB_MAJOR=	3
-SRCS=		bluetooth.c devaddr.c
 MAN=		bluetooth.3
 
-CFLAGS+=	-I${.CURDIR} -I${SYSDIR}
+WARNS?=		2
+CFLAGS+=	-I${.CURDIR} -I${.CURDIR}/../../sys
+
+SHLIB_MAJOR=	4
 
+SRCS=		bluetooth.c dev.c hci.c
 INCS=		bluetooth.h
-INCSDIR=	/usr/include
 
 MLINKS+=	bluetooth.3 bt_gethostbyname.3
 MLINKS+=	bluetooth.3 bt_gethostbyaddr.3
@@ -30,6 +30,24 @@ MLINKS+=	bluetooth.3 bt_aton.3
 MLINKS+=	bluetooth.3 bt_devaddr.3
 MLINKS+=	bluetooth.3 bt_devname.3
 
-CFLAGS+=	-I${.CURDIR} -I${SYSDIR}
+MLINKS+=	bluetooth.3 bt_devinfo.3
+MLINKS+=	bluetooth.3 bt_devenum.3
+
+MLINKS+=	bluetooth.3 bt_devopen.3
+MLINKS+=	bluetooth.3 bt_devclose.3
+MLINKS+=	bluetooth.3 bt_devsend.3
+MLINKS+=	bluetooth.3 bt_devreq.3
+MLINKS+=	bluetooth.3 bt_devfilter.3
+MLINKS+=	bluetooth.3 bt_devfilter_pkt_set.3
+MLINKS+=	bluetooth.3 bt_devfilter_pkt_clr.3
+MLINKS+=	bluetooth.3 bt_devfilter_pkt_tst.3
+MLINKS+=	bluetooth.3 bt_devfilter_evt_set.3
+MLINKS+=	bluetooth.3 bt_devfilter_evt_clr.3
+MLINKS+=	bluetooth.3 bt_devfilter_evt_tst.3
+MLINKS+=	bluetooth.3 bt_devinquiry.3
+
+MLINKS+=	bluetooth.3 bdaddr_same.3
+MLINKS+=	bluetooth.3 bdaddr_any.3
+MLINKS+=	bluetooth.3 bdaddr_copy.3
 
 .include <bsd.lib.mk>
diff --git a/lib/libbluetooth/bluetooth.3 b/lib/libbluetooth/bluetooth.3
index dff2d41d84..6066256027 100644
--- a/lib/libbluetooth/bluetooth.3
+++ b/lib/libbluetooth/bluetooth.3
@@ -1,6 +1,4 @@
-.\" $NetBSD: bluetooth.3,v 1.3 2006/07/30 00:15:54 wiz Exp $
-.\"
-.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" Copyright (c) 2003-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -24,10 +22,10 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $Id: bluetooth.3,v 1.3 2006/07/30 00:15:54 wiz Exp $
-.\" $FreeBSD: src/lib/libbluetooth/bluetooth.3,v 1.7 2005/01/21 10:26:11 ru Exp $
+.\" $Id: bluetooth.3,v 1.5 2003/05/20 23:04:30 max Exp $
+.\" $FreeBSD: head/lib/libbluetooth/bluetooth.3 267773 2014-06-23 08:23:05Z bapt $
 .\"
-.Dd July 26, 2006
+.Dd April 9, 2009
 .Dt BLUETOOTH 3
 .Os
 .Sh NAME
@@ -44,7 +42,25 @@
 .Nm bt_aton ,
 .Nm bt_ntoa ,
 .Nm bt_devaddr ,
-.Nm bt_devname
+.Nm bt_devname ,
+.Nm bt_devinfo ,
+.Nm bt_devenum ,
+.Nm bt_devopen ,
+.Nm bt_devclose ,
+.Nm bt_devsend ,
+.Nm bt_devrecv ,
+.Nm bt_devreq ,
+.Nm bt_devfilter ,
+.Nm bt_devfilter_pkt_set ,
+.Nm bt_devfilter_pkt_clr ,
+.Nm bt_devfilter_pkt_tst ,
+.Nm bt_devfilter_evt_set ,
+.Nm bt_devfilter_evt_clr ,
+.Nm bt_devfilter_evt_tst ,
+.Nm bt_devinquiry ,
+.Nm bdaddr_same ,
+.Nm bdaddr_any ,
+.Nm bdaddr_copy
 .Nd Bluetooth routines
 .Sh LIBRARY
 .Lb libbluetooth
@@ -53,7 +69,7 @@
 .Ft struct hostent *
 .Fn bt_gethostbyname "const char *name"
 .Ft struct hostent *
-.Fn bt_gethostbyaddr "const void *addr" "socklen_t len" "int type"
+.Fn bt_gethostbyaddr "const char *addr" "int len" "int type"
 .Ft struct hostent *
 .Fn bt_gethostent void
 .Ft void
@@ -75,16 +91,55 @@
 .Ft const char *
 .Fn bt_ntoa "const bdaddr_t *ba" "char *str"
 .Ft int
-.Fn bt_devaddr "const char *name" "bdaddr_t *addr"
+.Fn bt_devaddr "const char *devname" "bdaddr_t *addr"
+.Ft int
+.Fn bt_devname "char *devname" "const bdaddr_t *addr"
+.Ft int
+.Fn (bt_devenum_cb_t) "int s" "struct bt_devinfo const *di" "void *arg"
+.Ft int
+.Fn bt_devinfo "struct bt_devinfo *di"
+.Ft int
+.Fn bt_devenum "bt_devenum_cb_t *cb" "void *arg"
+.Ft int
+.Fn bt_devopen "char const *devname"
+.Ft int
+.Fn bt_devclose "int s"
+.Ft int
+.Fn bt_devsend "int s" "uint16_t opcode" "void *param" "size_t plen"
+.Ft ssize_t
+.Fn bt_devrecv "int s" "void *buf" "size_t size" "time_t to"
+.Ft int
+.Fn bt_devreq "int s" "struct bt_devreq *r" "time_t to"
+.Ft int
+.Fn bt_devfilter "int s" "struct bt_devfilter const *new" "struct bt_devfilter *old"
+.Ft void
+.Fn bt_devfilter_pkt_set "struct bt_devfilter *filter" "uint8_t type"
+.Ft void
+.Fn bt_devfilter_pkt_clt "struct bt_devfilter *filter" "uint8_t type"
+.Ft int
+.Fn bt_devfilter_pkt_tst "struct bt_devfilter const *filter" "uint8_t type"
+.Ft void
+.Fn bt_devfilter_evt_set "struct bt_devfilter *filter" "uint8_t event"
+.Ft void
+.Fn bt_devfilter_evt_clt "struct bt_devfilter *filter" "uint8_t event"
+.Ft int
+.Fn bt_devfilter_evt_tst "struct bt_devfilter const *filter" "uint8_t event"
+.Ft int
+.Fn bt_devinquiry "char const *devname" "time_t length" "int num_rsp" "struct bt_devinquiry **ii"
 .Ft int
-.Fn bt_devname "char *name" "const bdaddr_t *addr"
+.Fn bdaddr_same "const bdaddr_t *a" "const bdaddr_t *b"
+.Ft int
+.Fn bdaddr_any "const bdaddr_t *a"
+.Ft int
+.Fn bdaddr_copy "const bdaddr_t *dst" "const bdaddr_t *src"
 .Sh DESCRIPTION
 The
 .Fn bt_gethostent ,
-.Fn bt_gethostbyname ,
+.Fn bt_gethostbyname
 and
 .Fn bt_gethostbyaddr
-functions each return a pointer to an object with the
+functions
+each return a pointer to an object with the
 .Vt hostent
 structure describing a Bluetooth host
 referenced by name or by address, respectively.
@@ -136,7 +191,7 @@ file.
 .Pp
 The
 .Fn bt_getprotoent ,
-.Fn bt_getprotobyname ,
+.Fn bt_getprotobyname
 and
 .Fn bt_getprotobynumber
 functions each return a pointer to an object with the
@@ -155,8 +210,7 @@ The
 .Fa proto
 argument passed to
 .Fn bt_getprotobynumber
-should have numeric value of the desired Bluetooth Protocol Service
-Multiplexor.
+should have numeric value of the desired Bluetooth Protocol Service Multiplexor.
 .Pp
 The structure returned contains the information obtained from a line in
 .Pa /etc/bluetooth/protocols
@@ -193,19 +247,368 @@ takes a Bluetooth address and places an
 .Tn ASCII
 string representing the address into the buffer provided.
 It is up to the caller to ensure that provided buffer has enough space.
-If no buffer was provided then an internal static buffer will be used.
+If no buffer was provided then internal static buffer will be used.
 .Pp
 The
 .Fn bt_devaddr
-function interprets the specified character string as the
-address or device name of a Bluetooth device on the local system, and
-places the device address in the structure provided, if any.
-It returns 1 if the string was successfully interpreted,
-or 0 if the string did not match any local device. The
+function interprets the specified
+.Fa devname
+string as the address or device name of a Bluetooth device on the local system,
+and places the device address in the provided
+.Fa bdaddr ,
+if any.
+The function returns 1 if the string was successfully interpreted,
+or 0 if the string did not match any local device.
+The
 .Fn bt_devname
 function takes a Bluetooth device address and copies the local device
-name associated with that address into the buffer provided, if any.
-It returns 1 when the device was found, otherwise 0.
+name associated with that address into the buffer provided,
+if any.
+Caller must ensure that provided buffer is at least
+.Dv HCI_DEVNAME_SIZE
+characters in size.
+The function returns 1 when the device was found,
+otherwise 0.
+.Pp
+The
+.Fn bt_devinfo
+function populates provided
+.Vt bt_devinfo
+structure with the information about given Bluetooth device.
+The caller is expected to pass Bluetooth device name in the
+.Fa devname
+field of the passed
+.Vt bt_devinfo
+structure.
+The function returns 0 when successful,
+otherwise -1.
+The
+.Vt bt_devinfo
+structure is defined as follows
+.Bd -literal -offset indent
+struct bt_devinfo
+{
+        char            devname[HCI_DEVNAME_SIZE];
+
+        uint32_t        state;
+
+        bdaddr_t        bdaddr;
+        uint16_t        _reserved0;
+
+        uint8_t         features[HCI_DEVFEATURES_SIZE];
+
+        /* buffer info */
+        uint16_t        _reserved1;
+        uint16_t        cmd_free;
+        uint16_t        sco_size;
+        uint16_t        sco_pkts;
+        uint16_t        sco_free;
+        uint16_t        acl_size;
+        uint16_t        acl_pkts;
+        uint16_t        acl_free;
+
+        /* stats */
+        uint32_t        cmd_sent;
+        uint32_t        evnt_recv;
+        uint32_t        acl_recv;
+        uint32_t        acl_sent;
+        uint32_t        sco_recv;
+        uint32_t        sco_sent;
+        uint32_t        bytes_recv;
+        uint32_t        bytes_sent;
+
+        /* misc/specific */
+        uint16_t        link_policy_info;
+        uint16_t        packet_type_info;
+        uint16_t        role_switch_info;
+        uint16_t        debug;
+
+        uint8_t         _padding[20];
+};
+.Ed
+.Pp
+The
+.Fn bt_devenum
+function enumerates Bluetooth devices present in the system.
+For every device found,
+the function will call provided
+.Fa cb
+callback function which should be of
+.Vt bt_devenum_cb_t
+type.
+The callback function is passed a
+.Dv HCI
+socket
+.Fa s ,
+fully populated
+.Vt bt_devinfo
+structure
+.Fa di
+and
+.Fa arg
+argument provided to the
+.Fn bt_devenum .
+The callback function can stop enumeration by returning a value
+that is greater than zero.
+The function returns number of successfully enumerated devices,
+or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devopen
+function opens a Bluetooth device with the given
+.Fa devname
+and returns a connected and bound
+.Dv HCI
+socket handle.
+The function returns -1 if an error has occurred.
+.Pp
+The
+.Fn bt_devclose
+closes the passed
+.Dv HCI
+socket handle
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+.Pp
+The
+.Fn bt_devsend
+function sends a Bluetooth
+.Dv HCI
+command with the given
+.Fa opcode
+to the provided socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+The
+.Fa opcode
+parameter is expected to be in the host byte order.
+The
+.Fa param
+and
+.Fa plen
+parameters specify command parameters.
+The
+.Fn bt_devsend
+function does not modify the
+.Dv HCI
+filter on the provided socket
+.Fa s .
+The function returns 0 on success,
+or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devrecv
+function receives one Bluetooth
+.Dv HCI
+packet from the socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+The packet is placed into the provided buffer
+.Fa buf
+of size
+.Fa size .
+The
+.Fa to
+parameter specifies receive timeout in seconds.
+Infinite timeout can be specified by passing negative value in the
+.Fa to
+parameter.
+The
+.Fn bt_devrecv
+function does not modify the
+.Dv HCI
+filter on the provided socket
+.Fa s .
+The function returns total number of bytes received,
+or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devreq
+function makes a Bluetooth
+.Dv HCI
+request to the socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+The function will send the specified command and will wait for the specified
+event,
+or timeout
+.Fa to
+seconds to occur.
+The
+.Vt bt_devreq
+structure is defined as follows
+.Bd -literal -offset indent
+struct bt_devreq
+{
+        uint16_t        opcode;
+        uint8_t         event;
+        void            *cparam;
+        size_t          clen;
+        void            *rparam;
+        size_t          rlen;
+};
+.Ed
+.Pp
+The
+.Fa opcode
+field specifies the command and is expected to be in the host byte order.
+The
+.Fa cparam
+and
+.Fa clen
+fields specify command parameters data and command parameters data size
+respectively.
+The
+.Fa event
+field specifies which Bluetooth
+.Dv HCI
+event ID the function should wait for, otherwise it should be set to zero.
+The
+.Dv HCI
+Command Complete and Command Status events are enabled by default.
+The
+.Fa rparam
+and
+.Fa rlen
+parameters specify buffer and buffer size respectively where return
+parameters should be placed.
+The
+.Fn bt_devreq
+function temporarily modifies filter on the provided
+.Dv HCI
+socket
+.Fa s .
+The function returns 0 on success, or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devfilter
+controls the local
+.Dv HCI
+filter associated with the socket
+.Fa s ,
+previously obtained with
+.Xr bt_devopen 3 .
+Filtering can be done on packet types, i.e.
+.Dv ACL ,
+.Dv SCO
+or
+.Dv HCI ,
+command and event packets, and, in addition, on
+.Dv HCI
+event IDs.
+Before applying the
+.Fa new
+filter (if provided) the function will try to obtain the current filter
+from the socket
+.Fa s
+and place it into the
+.Fa old
+parameter (if provided).
+The function returns 0 on success, or -1 if an error occurred.
+.Pp
+The
+.Fn bt_devfilter_pkt_set ,
+.Fn bt_devfilter_pkt_clr
+and
+.Fn bt_devfilter_pkt_tst
+functions can be used to modify and test the
+.Dv HCI
+filter
+.Fa filter .
+The
+.Fa type
+parameter specifies
+.Dv HCI
+packet type.
+.Pp
+The
+.Fn bt_devfilter_evt_set ,
+.Fn bt_devfilter_evt_clr
+and
+.Fn bt_devfilter_evt_tst
+functions can be used to modify and test the
+.Dv HCI
+event filter
+.Fa filter .
+The
+.Fa event
+parameter specifies
+.Dv HCI
+event ID.
+.Pp
+The
+.Fn bt_devinquiry
+function performs Bluetooth inquiry.
+The
+.Fa devname
+parameter specifies which local Bluetooth device should perform an inquiry.
+If not specified, i.e.
+.Dv NULL ,
+then first available device will be used.
+The
+.Fa length
+parameters specifies the total length of an inquiry in seconds.
+If not specified, i.e. 0, default value will be used.
+The
+.Fa num_rsp
+parameter specifies the number of responses that can be received before
+the inquiry is halted.
+If not specified, i.e. 0, default value will be used.
+The
+.Fa ii
+parameter specifies where to place inquiry results.
+On success, the function will return total number of inquiry results,
+will allocate,
+using
+.Xr calloc 3 ,
+buffer to store all the inquiry results and
+will return pointer to the allocated buffer in the
+.Fa ii
+parameter.
+It is up to the caller of the function to dispose of the buffer using
+.Xr free 3
+call.
+The function returns -1 if an error has occurred.
+The
+.Vt bt_devinquiry
+structure is defined as follows
+.Bd -literal -offset indent
+struct bt_devinquiry {
+        bdaddr_t        bdaddr;
+        uint8_t         pscan_rep_mode;
+        uint8_t         pscan_period_mode;
+        uint8_t         dev_class[3];
+        uint16_t        clock_offset;
+        int8_t          rssi;
+        uint8_t         data[240];
+};
+.Ed
+.Pp
+The
+.Fn bdaddr_same ,
+.Fn bdaddr_any
+and
+.Fn bdaddr_copy
+are handy shorthand Bluetooth address utility functions.
+The
+.Fn bdaddr_same
+function will test if two provided BD_ADDRs are the same.
+The
+.Fn bdaddr_any
+function will test if provided BD_ADDR is
+.Dv ANY
+BD_ADDR.
+The
+.Fn bdaddr_copy
+function will copy provided
+.Fa src
+BD_ADDR into provided
+.Fa dst
+BD_ADDR.
 .Sh FILES
 .Bl -tag -width ".Pa /etc/bluetooth/hosts" -compact
 .It Pa /etc/bluetooth/hosts
@@ -218,19 +621,19 @@ const char *bdstr = "00:01:02:03:04:05";
 bdaddr_t bd;
 struct hostent *hp;
 
-if (!bt_aton(bdstr, \*[Am]bd))
+if (!bt_aton(bdstr, &bd))
 	errx(1, "can't parse BD_ADDR %s", bdstr);
 
-if ((hp = bt_gethostbyaddr(\*[Am]bd, sizeof(bd),
-    AF_BLUETOOTH)) == NULL)
+if ((hp = bt_gethostbyaddr((const char *)&bd,
+    sizeof(bd), AF_BLUETOOTH)) == NULL)
 	errx(1, "no name associated with %s", bdstr);
 
-printf("name associated with %s is %s\en", bdstr, hp-\*[Gt]h_name);
+printf("name associated with %s is %s\en", bdstr, hp->h_name);
 .Ed
 .Sh DIAGNOSTICS
 Error return status from
 .Fn bt_gethostent ,
-.Fn bt_gethostbyname ,
+.Fn bt_gethostbyname
 and
 .Fn bt_gethostbyaddr
 is indicated by return of a
@@ -263,7 +666,7 @@ This is a non-recoverable error.
 .Pp
 The
 .Fn bt_getprotoent ,
-.Fn bt_getprotobyname ,
+.Fn bt_getprotobyname
 and
 .Fn bt_getprotobynumber
 return
@@ -276,23 +679,9 @@ on EOF or error.
 .Xr getprotobynumber 3 ,
 .Xr herror 3 ,
 .Xr inet_aton 3 ,
-.Xr inet_ntoa 3
-.Sh HISTORY
-.Nm libbluetooth
-first appeared in
-.Fx
-was ported to
-.Nx 4.0
-and extended by
-.An Iain Hibbert
-for Itronix, Inc.
-.Nm libbluetooth
-was imported into
-.Dx 1.11 .
-.Sh AUTHORS
-.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
-.An Iain Hibbert
-.Sh CAVEATS
+.Xr inet_ntoa 3 ,
+.Xr ng_hci 4
+.Sh CAVEAT
 The
 .Fn bt_gethostent
 function reads the next line of
@@ -316,7 +705,23 @@ The
 function opens and/or rewinds the
 .Pa /etc/bluetooth/protocols
 file.
+.Pp
+The
+.Fn bt_devenum
+function enumerates up to
+.Dv HCI_DEVMAX
+Bluetooth devices.
+During enumeration the
+.Fn bt_devenum
+function uses the same
+.Dv HCI
+socket.
+The function guarantees that the socket,
+passed to the callback function,
+will be bound and connected to the Bluetooth device being enumerated.
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
 .Sh BUGS
-These functions use static data storage;
+Some of those functions use static data storage;
 if the data is needed for future use, it should be
 copied before any subsequent calls overwrite it.
diff --git a/lib/libbluetooth/bluetooth.c b/lib/libbluetooth/bluetooth.c
index ba1efb16a5..93113eb8d3 100644
--- a/lib/libbluetooth/bluetooth.c
+++ b/lib/libbluetooth/bluetooth.c
@@ -1,9 +1,9 @@
-/* $NetBSD: bluetooth.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
-
 /*
  * bluetooth.c
- *
- * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2001-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,8 +27,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: bluetooth.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
- * $FreeBSD: src/lib/libbluetooth/bluetooth.c,v 1.2 2004/03/05 08:10:17 markm Exp $
+ * $Id: bluetooth.c,v 1.3 2003/05/20 23:04:30 max Exp $
+ * $FreeBSD: head/lib/libbluetooth/bluetooth.c 189462 2009-03-06 23:30:07Z emax $
  */
 
 #include <bluetooth.h>
@@ -67,7 +67,7 @@ bt_gethostbyname(char const *name)
 	while ((p = bt_gethostent()) != NULL) {
 		if (strcasecmp(p->h_name, name) == 0)
 			break;
-		for (cp = p->h_aliases; *cp != NULL; cp++)
+		for (cp = p->h_aliases; *cp != 0; cp++)
 			if (strcasecmp(*cp, name) == 0)
 				goto found;
 	}
@@ -78,7 +78,7 @@ bt_gethostbyname(char const *name)
 }
 
 struct hostent *
-bt_gethostbyaddr(void const *addr, socklen_t len, int type)
+bt_gethostbyaddr(char const *addr, int len, int type)
 {
 	struct hostent	*p;
 
@@ -89,7 +89,7 @@ bt_gethostbyaddr(void const *addr, socklen_t len, int type)
 
 	bt_sethostent(host_stayopen);
 	while ((p = bt_gethostent()) != NULL)
-		if (p->h_addrtype == type && memcmp(p->h_addr, addr, len) == 0)
+		if (p->h_addrtype == type && bcmp(p->h_addr, addr, len) == 0)
 			break;
 	bt_endhostent();
 
@@ -121,7 +121,7 @@ bt_gethostent(void)
 	if ((cp = strpbrk(p, " \t")) == NULL)
 		goto again;
 	*cp++ = 0;
-	if (bt_aton(p, &host_addr) == 0)
+	if (bt_aton(p, &host_addr) == 0) 
 		goto again;
 	host_addr_ptrs[0] = (char *) &host_addr;
 	host_addr_ptrs[1] = NULL;
@@ -180,7 +180,7 @@ bt_getprotobyname(char const *name)
 	while ((p = bt_getprotoent()) != NULL) {
 		if (strcmp(p->p_name, name) == 0)
 			break;
-		for (cp = p->p_aliases; *cp != NULL; cp++)
+		for (cp = p->p_aliases; *cp != 0; cp++)
 			if (strcmp(*cp, name) == 0)
 				goto found;
 	}
@@ -191,13 +191,13 @@ bt_getprotobyname(char const *name)
 }
 
 struct protoent *
-bt_getprotobynumber(int num)
+bt_getprotobynumber(int proto)
 {
 	struct protoent	*p;
 
 	bt_setprotoent(proto_stayopen);
 	while ((p = bt_getprotoent()) != NULL)
-		if (p->p_proto == num)
+		if (p->p_proto == proto)
 			break;
 	bt_endprotoent();
 
@@ -230,7 +230,7 @@ bt_getprotoent(void)
 		cp++;
 	if ((p = strpbrk(cp, " \t")) != NULL)
 		*p++ = '\0';
-	proto.p_proto = (int)strtol(cp, NULL, 0);
+	proto.p_proto = atoi(cp);
 	q = proto.p_aliases = proto_aliases;
 	if (p != NULL) {
 		cp = p;
@@ -308,7 +308,7 @@ bt_aton(char const *str, bdaddr_t *ba)
 			b = -1;
 			break;
 		}
-
+		
 		if (b < 0)
 			return (0);
 
@@ -368,3 +368,4 @@ bt_hex_nibble(char nibble)
 
 	return (-1);
 }
+
diff --git a/lib/libbluetooth/bluetooth.h b/lib/libbluetooth/bluetooth.h
index baadadb43f..33c6202bd4 100644
--- a/lib/libbluetooth/bluetooth.h
+++ b/lib/libbluetooth/bluetooth.h
@@ -1,10 +1,9 @@
-/* $NetBSD: bluetooth.h,v 1.3 2006/09/26 19:18:19 plunky Exp $ */
-/* $DragonFly: src/lib/libbluetooth/bluetooth.h,v 1.1 2008/01/03 11:47:52 hasso Exp $ */
-
 /*
  * bluetooth.h
- *
- * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ */
+
+/*-
+ * Copyright (c) 2001-2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -28,88 +27,190 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: bluetooth.h,v 1.3 2006/09/26 19:18:19 plunky Exp $
- * $FreeBSD: src/lib/libbluetooth/bluetooth.h,v 1.2 2005/03/17 21:39:44 emax Exp $
+ * $Id: bluetooth.h,v 1.5 2003/09/14 23:28:42 max Exp $
+ * $FreeBSD: head/lib/libbluetooth/bluetooth.h 213042 2010-09-22 23:41:02Z emax $
  */
 
 #ifndef _BLUETOOTH_H_
 #define _BLUETOOTH_H_
 
 #include <sys/types.h>
+#include <bitstring.h>		/* XXX */
 #include <sys/endian.h>
+#include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <errno.h>
 #include <netdb.h>
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-#include <stdio.h>
+#include <netgraph7/ng_message.h>
+#include <netgraph7/bluetooth/include/ng_hci.h>
+#include <netgraph7/bluetooth/include/ng_l2cap.h>
+#include <netgraph7/bluetooth/include/ng_btsocket.h>
+#include <time.h>
 
 __BEGIN_DECLS
 
+/*
+ * Linux BlueZ compatibility
+ */
+
+#define	bacmp(ba1, ba2)	memcmp((ba1), (ba2), sizeof(bdaddr_t))
+#define	bacpy(dst, src)	memcpy((dst), (src), sizeof(bdaddr_t))
+#define ba2str(ba, str)	bt_ntoa((ba), (str))
+#define str2ba(str, ba)	(bt_aton((str), (ba)) == 1? 0 : -1)
+#define htobs(d)	htole16(d)
+#define htobl(d)	htole32(d)
+#define btohs(d)	le16toh(d)
+#define btohl(d)	le32toh(d)
+
 /*
  * Interface to the outside world
  */
 
-struct hostent *  bt_gethostbyname    (char const *);
-struct hostent *  bt_gethostbyaddr    (void const *, socklen_t, int);
+struct hostent *  bt_gethostbyname    (char const *name);
+struct hostent *  bt_gethostbyaddr    (char const *addr, int len, int type);
 struct hostent *  bt_gethostent       (void);
-void              bt_sethostent       (int);
+void              bt_sethostent       (int stayopen);
 void              bt_endhostent       (void);
 
-struct protoent * bt_getprotobyname   (char const *);
-struct protoent * bt_getprotobynumber (int);
+struct protoent * bt_getprotobyname   (char const *name);
+struct protoent * bt_getprotobynumber (int proto);
 struct protoent * bt_getprotoent      (void);
-void              bt_setprotoent      (int);
+void              bt_setprotoent      (int stayopen);
 void              bt_endprotoent      (void);
 
-char const *      bt_ntoa             (bdaddr_t const *, char *);
-int               bt_aton             (char const *, bdaddr_t *);
+char const *      bt_ntoa             (bdaddr_t const *ba, char *str);
+int               bt_aton             (char const *str, bdaddr_t *ba);
 
-int               bt_devaddr          (const char *, bdaddr_t *);
-int               bt_devname          (char *, const bdaddr_t *);
+/* bt_devXXXX() functions (inspired by NetBSD) */
+int               bt_devaddr          (char const *devname, bdaddr_t *addr);
+int               bt_devname          (char *devname, bdaddr_t const *addr);
 
-/*
- * bthcid(8) PIN Client API
+/* 
+ * Bluetooth HCI functions
  */
 
-/* Client PIN Request packet */
-typedef struct {
-	bdaddr_t	laddr;			/* local address */
-	bdaddr_t	raddr;			/* remote address */
-	uint8_t		time;			/* validity (seconds) */
-} __attribute__ ((packed)) bthcid_pin_request_t;
-
-/* Client PIN Response packet */
-typedef struct {
-	bdaddr_t	laddr;			/* local address */
-	bdaddr_t	raddr;			/* remote address */
-	uint8_t		pin[HCI_PIN_SIZE];	/* PIN */
-} __attribute__ ((packed)) bthcid_pin_response_t;
-
-/* Default socket name */
-#define BTHCID_SOCKET_NAME	"/var/run/bthcid"
-
-#define COMPAT_BLUEZ 
-#ifdef COMPAT_BLUEZ
+#define	HCI_DEVMAX			32		/* arbitrary */
+#define	HCI_DEVNAME_SIZE		NG_NODESIZ
+#define	HCI_DEVFEATURES_SIZE		NG_HCI_FEATURES_SIZE
+
+struct bt_devinfo
+{
+	char		devname[HCI_DEVNAME_SIZE];
+
+	uint32_t	state;		/* device/implementation specific */
+
+	bdaddr_t	bdaddr;
+	uint16_t	_reserved0;
+
+	uint8_t		features[HCI_DEVFEATURES_SIZE];
+
+	/* buffer info */
+	uint16_t	_reserved1;
+	uint16_t	cmd_free;
+	uint16_t	sco_size;
+	uint16_t	sco_pkts;
+	uint16_t	sco_free;
+	uint16_t	acl_size;
+	uint16_t	acl_pkts;
+	uint16_t	acl_free;
+
+	/* stats */
+	uint32_t	cmd_sent;
+	uint32_t	evnt_recv;
+	uint32_t	acl_recv;
+	uint32_t	acl_sent;
+	uint32_t	sco_recv;
+	uint32_t	sco_sent;
+	uint32_t	bytes_recv;
+	uint32_t	bytes_sent;
+
+	/* misc/specific */
+	uint16_t	link_policy_info;
+	uint16_t	packet_type_info;
+	uint16_t	role_switch_info;
+	uint16_t	debug;
+
+	uint8_t		_padding[20];	/* leave space for future additions */
+};
+
+struct bt_devreq
+{
+	uint16_t	opcode;
+	uint8_t		event;
+	void		*cparam;
+	size_t		clen;
+	void		*rparam;
+	size_t		rlen;
+};
+
+struct bt_devfilter {
+	bitstr_t	bit_decl(packet_mask, 8);
+	bitstr_t	bit_decl(event_mask, 256);
+};
+
+struct bt_devinquiry {
+	bdaddr_t        bdaddr;
+	uint8_t         pscan_rep_mode;
+	uint8_t         pscan_period_mode;
+	uint8_t         dev_class[3];
+	uint16_t        clock_offset;
+	int8_t          rssi;
+	uint8_t         data[240];
+};
+
+typedef int	(bt_devenum_cb_t)(int, struct bt_devinfo const *, void *);
+
+int		bt_devopen (char const *devname);
+int		bt_devclose(int s);
+int		bt_devsend (int s, uint16_t opcode, void *param, size_t plen);
+ssize_t		bt_devrecv (int s, void *buf, size_t size, time_t to);
+int		bt_devreq  (int s, struct bt_devreq *r, time_t to);
+int		bt_devfilter(int s, struct bt_devfilter const *newp,
+			     struct bt_devfilter *oldp);
+void		bt_devfilter_pkt_set(struct bt_devfilter *filter, uint8_t type);
+void		bt_devfilter_pkt_clr(struct bt_devfilter *filter, uint8_t type);
+int		bt_devfilter_pkt_tst(struct bt_devfilter const *filter, uint8_t type);
+void		bt_devfilter_evt_set(struct bt_devfilter *filter, uint8_t event);
+void		bt_devfilter_evt_clr(struct bt_devfilter *filter, uint8_t event);
+int		bt_devfilter_evt_tst(struct bt_devfilter const *filter, uint8_t event);
+int		bt_devinquiry(char const *devname, time_t length, int num_rsp,
+			      struct bt_devinquiry **ii);
+int		bt_devinfo (struct bt_devinfo *di);
+int		bt_devenum (bt_devenum_cb_t *cb, void *arg);
+
 /*
- * Linux BlueZ compatibility
+ * bdaddr utility functions (from NetBSD)
  */
 
-#define	bacmp(ba1, ba2)	memcmp((ba1), (ba2), sizeof(bdaddr_t))
-#define	bacpy(dst, src)	memcpy((dst), (src), sizeof(bdaddr_t))
-#define ba2str(ba, str)	bt_ntoa((ba), (str))
-#define str2ba(str, ba)	(bt_aton((str), (ba)) == 1 ? 0 : -1)
-
-#define htobs(x)	htole16(x)
-#define htobl(x)	htole32(x)
-#define btohs(x)	le16toh(x)
-#define btohl(x)	le32toh(x)
-
-#define bt_malloc(n)	malloc(n)
-#define bt_free(p)	free(p)
-
-#endif	/* COMPAT_BLUEZ */
+static __inline int
+bdaddr_same(const bdaddr_t *a, const bdaddr_t *b)
+{
+	return (a->b[0] == b->b[0] && a->b[1] == b->b[1] &&
+		a->b[2] == b->b[2] && a->b[3] == b->b[3] &&
+		a->b[4] == b->b[4] && a->b[5] == b->b[5]);
+}
+
+static __inline int
+bdaddr_any(const bdaddr_t *a)
+{
+	return (a->b[0] == 0 && a->b[1] == 0 && a->b[2] == 0 &&
+		a->b[3] == 0 && a->b[4] == 0 && a->b[5] == 0);
+}
+
+static __inline void
+bdaddr_copy(bdaddr_t *d, const bdaddr_t *s)
+{
+	d->b[0] = s->b[0];
+	d->b[1] = s->b[1];
+	d->b[2] = s->b[2];
+	d->b[3] = s->b[3];
+	d->b[4] = s->b[4];
+	d->b[5] = s->b[5];
+}
 
 __END_DECLS
 
 #endif /* ndef _BLUETOOTH_H_ */
+
diff --git a/lib/libbluetooth/dev.c b/lib/libbluetooth/dev.c
new file mode 100644
index 0000000000..076b6f6697
--- /dev/null
+++ b/lib/libbluetooth/dev.c
@@ -0,0 +1,95 @@
+/*
+ * dev.c
+ */
+
+/*-
+ * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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: head/lib/libbluetooth/dev.c 189462 2009-03-06 23:30:07Z emax $
+ */
+
+#include <bluetooth.h>
+#include <stdio.h>
+#include <string.h>
+
+struct bt_devaddr_match_arg
+{
+	char		devname[HCI_DEVNAME_SIZE];
+	bdaddr_t const	*bdaddr;
+};
+
+static bt_devenum_cb_t	bt_devaddr_match;
+
+int
+bt_devaddr(char const *devname, bdaddr_t *addr)
+{
+	struct bt_devinfo	di;
+
+	strlcpy(di.devname, devname, sizeof(di.devname));
+
+	if (bt_devinfo(&di) < 0)
+		return (0);
+
+	if (addr != NULL)
+		bdaddr_copy(addr, &di.bdaddr);
+
+	return (1);
+}
+
+int
+bt_devname(char *devname, bdaddr_t const *addr)
+{
+	struct bt_devaddr_match_arg	arg;
+
+	memset(&arg, 0, sizeof(arg));
+	arg.bdaddr = addr;
+
+	if (bt_devenum(&bt_devaddr_match, &arg) < 0)
+		return (0);
+	
+	if (arg.devname[0] == '\0') {
+		errno = ENXIO;
+		return (0);
+	}
+
+	if (devname != NULL)
+		strlcpy(devname, arg.devname, HCI_DEVNAME_SIZE);
+
+	return (1);
+}
+
+static int
+bt_devaddr_match(int s, struct bt_devinfo const *di, void *arg)
+{
+	struct bt_devaddr_match_arg	*m = (struct bt_devaddr_match_arg *)arg;
+
+	if (!bdaddr_same(&di->bdaddr, m->bdaddr))
+		return (0);
+
+	strlcpy(m->devname, di->devname, sizeof(m->devname));
+
+	return (1);
+}
+
diff --git a/lib/libbluetooth/devaddr.c b/lib/libbluetooth/devaddr.c
deleted file mode 100644
index 5c787d7730..0000000000
--- a/lib/libbluetooth/devaddr.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* $NetBSD: devaddr.c,v 1.2 2006/08/28 08:24:39 plunky Exp $ */
-/* $DragonFly: src/lib/libbluetooth/devaddr.c,v 1.1 2008/01/03 11:47:52 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/ioctl.h>
-#include <bluetooth.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-int
-bt_devaddr(const char *name, bdaddr_t *addr)
-{
-	struct btreq btr;
-	bdaddr_t bdaddr;
-	int s, rv;
-
-	if (name == NULL) {
-		errno = EINVAL;
-		return 0;
-	}
-
-	if (addr == NULL)
-		addr = &bdaddr;
-
-	if (bt_aton(name, addr))
-		return bt_devname(NULL, addr);
-
-	memset(&btr, 0, sizeof(btr));
-	strlcpy(btr.btr_name, name, HCI_DEVNAME_SIZE);
-
-	s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
-	if (s == -1)
-		return 0;
-
-	rv = ioctl(s, SIOCGBTINFO, &btr);
-	close(s);
-
-	if (rv == -1)
-		return 0;
-
-	if ((btr.btr_flags & BTF_UP) == 0) {
-		errno = ENXIO;
-		return 0;
-	}
-
-	bdaddr_copy(addr, &btr.btr_bdaddr);
-	return 1;
-}
-
-int
-bt_devname(char *name, const bdaddr_t *addr)
-{
-	struct btreq btr;
-	int s, rv;
-
-	if (addr == NULL) {
-		errno = EINVAL;
-		return 0;
-	}
-
-	memset(&btr, 0, sizeof(btr));
-	bdaddr_copy(&btr.btr_bdaddr, addr);
-
-	s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
-	if (s == -1)
-		return 0;
-
-	rv = ioctl(s, SIOCGBTINFOA, &btr);
-	close(s);
-
-	if (rv == -1)
-		return 0;
-
-	if ((btr.btr_flags & BTF_UP) == 0) {
-		errno = ENXIO;
-		return 0;
-	}
-
-	if (name != NULL)
-		strlcpy(name, btr.btr_name, HCI_DEVNAME_SIZE);
-
-	return 1;
-}
diff --git a/lib/libbluetooth/hci.c b/lib/libbluetooth/hci.c
new file mode 100644
index 0000000000..34d150a9f2
--- /dev/null
+++ b/lib/libbluetooth/hci.c
@@ -0,0 +1,734 @@
+/*
+ * hci.c
+ */
+
+/*-
+ * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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: head/lib/libbluetooth/hci.c 192113 2009-05-14 17:10:19Z emax $
+ */
+
+#include <assert.h>
+#include <bluetooth.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#undef	MIN
+#define	MIN(a, b)	(((a) < (b))? (a) : (b))
+
+static int    bt_devany_cb(int s, struct bt_devinfo const *di, void *xdevname);
+static char * bt_dev2node (char const *devname, char *nodename, int nnlen);
+
+int
+bt_devopen(char const *devname)
+{
+	struct sockaddr_hci	ha;
+	bdaddr_t		ba;
+	int			s;
+
+	if (devname == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	memset(&ha, 0, sizeof(ha));
+	ha.hci_len = sizeof(ha);
+	ha.hci_family = AF_BLUETOOTH;
+
+	if (bt_aton(devname, &ba)) {
+		if (!bt_devname(ha.hci_node, &ba))
+			return (-1);
+	} else if (bt_dev2node(devname, ha.hci_node,
+					sizeof(ha.hci_node)) == NULL) {
+		errno = ENXIO;
+		return (-1);
+	}
+
+	s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
+	if (s < 0)
+		return (-1);
+
+	if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 ||
+	    connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0) {
+		close(s);
+		return (-1);
+	}
+
+	return (s);
+}
+
+int
+bt_devclose(int s)
+{
+	return (close(s));
+}
+
+int
+bt_devsend(int s, uint16_t opcode, void *param, size_t plen)
+{
+	ng_hci_cmd_pkt_t	h;
+	struct iovec		iv[2];
+	int			ivn;
+
+	if ((plen == 0 && param != NULL) ||
+	    (plen > 0 && param == NULL) ||
+	    plen > UINT8_MAX) { 
+		errno = EINVAL;
+		return (-1);
+	}
+
+	iv[0].iov_base = &h;
+	iv[0].iov_len = sizeof(h);
+	ivn = 1;
+
+	h.type = NG_HCI_CMD_PKT;
+	h.opcode = htole16(opcode);
+	if (plen > 0) {
+		h.length = plen;
+
+		iv[1].iov_base = param;
+		iv[1].iov_len = plen;
+		ivn = 2;
+	} else
+		h.length = 0;
+
+	while (writev(s, iv, ivn) < 0) {
+		if (errno == EAGAIN || errno == EINTR)
+			continue;
+
+		return (-1);
+	}
+
+	return (0);
+}
+
+ssize_t
+bt_devrecv(int s, void *buf, size_t size, time_t to)
+{
+	ssize_t	n;
+
+	if (buf == NULL || size == 0) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (to >= 0) {
+		fd_set		rfd;
+		struct timeval	tv;
+
+		FD_ZERO(&rfd);
+		FD_SET(s, &rfd);
+
+		tv.tv_sec = to;
+		tv.tv_usec = 0;
+
+		while ((n = select(s + 1, &rfd, NULL, NULL, &tv)) < 0) {
+			if (errno == EAGAIN || errno == EINTR)
+				continue;
+
+			return (-1);
+		}
+
+		if (n == 0) {
+			errno = ETIMEDOUT;
+			return (-1);
+		}
+
+		assert(FD_ISSET(s, &rfd));
+	}
+
+	while ((n = read(s, buf, size)) < 0) {
+		if (errno == EAGAIN || errno == EINTR)
+			continue;
+
+		return (-1);
+	}
+
+	switch (*((uint8_t *) buf)) {
+	case NG_HCI_CMD_PKT: {
+		ng_hci_cmd_pkt_t	*h = (ng_hci_cmd_pkt_t *) buf;
+
+		if (n >= sizeof(*h) && n == (sizeof(*h) + h->length))
+			return (n);
+		} break;
+
+	case NG_HCI_ACL_DATA_PKT: {
+		ng_hci_acldata_pkt_t	*h = (ng_hci_acldata_pkt_t *) buf;
+
+		if (n >= sizeof(*h) && n == (sizeof(*h) + le16toh(h->length)))
+			return (n);
+		} break;
+
+	case NG_HCI_SCO_DATA_PKT: {
+		ng_hci_scodata_pkt_t	*h = (ng_hci_scodata_pkt_t *) buf;
+
+		if (n >= sizeof(*h) && n == (sizeof(*h) + h->length))
+			return (n);
+		} break;
+
+	case NG_HCI_EVENT_PKT: {
+		ng_hci_event_pkt_t	*h = (ng_hci_event_pkt_t *) buf;
+
+		if (n >= sizeof(*h) && n == (sizeof(*h) + h->length))
+			return (n);
+		} break;
+	}
+
+	errno = EIO;
+	return (-1);
+}
+
+int
+bt_devreq(int s, struct bt_devreq *r, time_t to)
+{
+	uint8_t				buf[320]; /* more than enough */
+	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) buf;
+	ng_hci_command_compl_ep		*cc = (ng_hci_command_compl_ep *)(e+1);
+	ng_hci_command_status_ep	*cs = (ng_hci_command_status_ep*)(e+1);
+	struct bt_devfilter		old, new;
+	time_t				t_end;
+	uint16_t			opcode;
+	ssize_t				n;
+	int				error;
+
+	if (s < 0 || r == NULL || to < 0) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if ((r->rlen == 0 && r->rparam != NULL) ||
+	    (r->rlen > 0 && r->rparam == NULL)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	memset(&new, 0, sizeof(new));
+	bt_devfilter_pkt_set(&new, NG_HCI_EVENT_PKT);
+	bt_devfilter_evt_set(&new, NG_HCI_EVENT_COMMAND_COMPL);
+	bt_devfilter_evt_set(&new, NG_HCI_EVENT_COMMAND_STATUS);
+	if (r->event != 0)
+		bt_devfilter_evt_set(&new, r->event);
+
+	if (bt_devfilter(s, &new, &old) < 0)
+		return (-1);
+
+	error = 0;
+
+	n = bt_devsend(s, r->opcode, r->cparam, r->clen);
+	if (n < 0) {
+		error = errno;
+		goto out;	
+	}
+
+	opcode = htole16(r->opcode);
+	t_end = time(NULL) + to;
+
+	do {
+		to = t_end - time(NULL);
+		if (to < 0)
+			to = 0;
+
+		n = bt_devrecv(s, buf, sizeof(buf), to);
+		if (n < 0) {
+			error = errno;
+			goto out;
+		}
+
+		if (e->type != NG_HCI_EVENT_PKT) {
+			error = EIO;
+			goto out;
+		}
+
+		n -= sizeof(*e);
+
+		switch (e->event) {
+		case NG_HCI_EVENT_COMMAND_COMPL:
+			if (cc->opcode == opcode) {
+				n -= sizeof(*cc);
+
+				if (r->rlen >= n) {
+					r->rlen = n;
+					memcpy(r->rparam, cc + 1, r->rlen);
+				}
+
+				goto out;
+			}
+			break;
+
+		case NG_HCI_EVENT_COMMAND_STATUS:
+			if (cs->opcode == opcode) {
+				if (r->event != NG_HCI_EVENT_COMMAND_STATUS) {
+					if (cs->status != 0) {
+						error = EIO;
+						goto out;
+					}
+				} else {
+					if (r->rlen >= n) {
+						r->rlen = n;
+						memcpy(r->rparam, cs, r->rlen);
+					}
+
+					goto out;
+				}
+			}
+			break;
+
+		default:
+			if (e->event == r->event) {
+				if (r->rlen >= n) {
+					r->rlen = n;
+					memcpy(r->rparam, e + 1, r->rlen);
+				}
+
+				goto out;
+			}
+			break;
+		}
+	} while (to > 0);
+
+	error = ETIMEDOUT;
+out:
+	bt_devfilter(s, &old, NULL);
+
+	if (error != 0) {
+		errno = error;
+		return (-1);
+	}
+
+	return (0);
+}
+
+int
+bt_devfilter(int s, struct bt_devfilter const *new, struct bt_devfilter *old)
+{
+	struct ng_btsocket_hci_raw_filter	f;
+	socklen_t				len;
+
+	if (new == NULL && old == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (old != NULL) {
+		len = sizeof(f);
+		if (getsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER, &f, &len) < 0)
+			return (-1);
+
+		memset(old, 0, sizeof(*old));
+		memcpy(old->packet_mask, &f.packet_mask,
+			MIN(sizeof(old->packet_mask), sizeof(f.packet_mask)));
+		memcpy(old->event_mask, &f.event_mask,
+			MIN(sizeof(old->event_mask), sizeof(f.packet_mask)));
+	}
+
+	if (new != NULL) {
+		memset(&f, 0, sizeof(f));
+		memcpy(&f.packet_mask, new->packet_mask,
+			MIN(sizeof(f.packet_mask), sizeof(new->event_mask)));
+		memcpy(&f.event_mask, new->event_mask,
+			MIN(sizeof(f.event_mask), sizeof(new->event_mask)));
+
+		len = sizeof(f);
+		if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER, &f, len) < 0)
+			return (-1);
+	}
+
+	return (0);
+}
+
+void
+bt_devfilter_pkt_set(struct bt_devfilter *filter, uint8_t type)
+{
+	bit_set(filter->packet_mask, type - 1);
+}
+
+void
+bt_devfilter_pkt_clr(struct bt_devfilter *filter, uint8_t type)
+{
+	bit_clear(filter->packet_mask, type - 1);
+}
+
+int
+bt_devfilter_pkt_tst(struct bt_devfilter const *filter, uint8_t type)
+{
+	return (bit_test(filter->packet_mask, type - 1));
+}
+
+void
+bt_devfilter_evt_set(struct bt_devfilter *filter, uint8_t event)
+{
+	bit_set(filter->event_mask, event - 1);
+}
+
+void
+bt_devfilter_evt_clr(struct bt_devfilter *filter, uint8_t event)
+{
+	bit_clear(filter->event_mask, event - 1);
+}
+
+int
+bt_devfilter_evt_tst(struct bt_devfilter const *filter, uint8_t event)
+{
+	return (bit_test(filter->event_mask, event - 1));
+}
+
+int
+bt_devinquiry(char const *devname, time_t length, int num_rsp,
+		struct bt_devinquiry **ii)
+{
+	uint8_t				buf[320];
+	char				_devname[HCI_DEVNAME_SIZE];
+	struct bt_devfilter		f;
+	ng_hci_inquiry_cp		*cp = (ng_hci_inquiry_cp *) buf;
+	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) buf;
+	ng_hci_inquiry_result_ep	*ep = (ng_hci_inquiry_result_ep *)(e+1);
+	ng_hci_inquiry_response		*ir;
+	struct bt_devinquiry		*i;
+	int				s, n;
+
+	if (ii == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (devname == NULL) {
+		memset(_devname, 0, sizeof(_devname));
+		devname = _devname;
+
+		n = bt_devenum(bt_devany_cb, _devname);
+		if (n <= 0) {
+			if (n == 0)
+				*ii = NULL;
+
+			return (n);
+		}
+	}
+
+	s = bt_devopen(devname);
+	if (s < 0)
+		return (-1);
+
+	if (bt_devfilter(s, NULL, &f) < 0) {
+		bt_devclose(s);
+		return (-1);
+	}
+
+	bt_devfilter_evt_set(&f, NG_HCI_EVENT_INQUIRY_COMPL);
+	bt_devfilter_evt_set(&f, NG_HCI_EVENT_INQUIRY_RESULT);
+
+	if (bt_devfilter(s, &f, NULL) < 0) {
+		bt_devclose(s);
+		return (-1);
+	}
+
+	/* Always use GIAC LAP */
+	cp->lap[0] = 0x33;
+	cp->lap[1] = 0x8b;
+	cp->lap[2] = 0x9e;
+
+	/*
+	 * Calculate inquire length in 1.28 second units
+	 * v2.x specification says that 1.28 -> 61.44 seconds
+	 * range is acceptable
+	 */
+
+	if (length <= 0)
+		length = 5;
+	else if (length == 1)
+		length = 2;
+	else if (length > 62)
+		length = 62;
+
+	cp->inquiry_length = (uint8_t)((length * 100) / 128);
+
+	if (num_rsp <= 0 || num_rsp > 255)
+		num_rsp = 8;
+	cp->num_responses = (uint8_t) num_rsp;
+
+	i = *ii = calloc(num_rsp, sizeof(struct bt_devinquiry));
+	if (i == NULL) {
+		bt_devclose(s);
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	if (bt_devsend(s,
+		NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_INQUIRY),
+			cp, sizeof(*cp)) < 0) {
+		free(i);
+		bt_devclose(s);
+		return (-1);
+	}
+
+wait_for_more:
+
+	n = bt_devrecv(s, buf, sizeof(buf), length);
+	if (n < 0) {
+		free(i);
+		bt_devclose(s);
+		return (-1);
+	}
+
+	if (n < sizeof(ng_hci_event_pkt_t)) {
+		free(i);
+		bt_devclose(s);
+		errno = EIO;
+		return (-1);
+	}
+
+	switch (e->event) {
+	case NG_HCI_EVENT_INQUIRY_COMPL:
+		break;
+
+	case NG_HCI_EVENT_INQUIRY_RESULT:
+		ir = (ng_hci_inquiry_response *)(ep + 1);
+
+		for (n = 0; n < MIN(ep->num_responses, num_rsp); n ++) {
+			bdaddr_copy(&i->bdaddr, &ir->bdaddr);
+			i->pscan_rep_mode = ir->page_scan_rep_mode;
+			i->pscan_period_mode = ir->page_scan_period_mode;
+			memcpy(i->dev_class, ir->uclass, sizeof(i->dev_class));
+			i->clock_offset = le16toh(ir->clock_offset);
+
+			ir ++;
+			i ++;
+			num_rsp --;
+		}
+		/* FALLTHROUGH */
+
+	default:
+		goto wait_for_more;
+		/* NOT REACHED */
+	}
+
+	bt_devclose(s);
+		
+	return (i - *ii);
+}
+
+int
+bt_devinfo(struct bt_devinfo *di)
+{
+	union {
+		struct ng_btsocket_hci_raw_node_state		r0;
+		struct ng_btsocket_hci_raw_node_bdaddr		r1;
+		struct ng_btsocket_hci_raw_node_features	r2;
+		struct ng_btsocket_hci_raw_node_buffer		r3;
+		struct ng_btsocket_hci_raw_node_stat		r4;
+		struct ng_btsocket_hci_raw_node_link_policy_mask r5;
+		struct ng_btsocket_hci_raw_node_packet_mask	r6;
+		struct ng_btsocket_hci_raw_node_role_switch	r7;
+		struct ng_btsocket_hci_raw_node_debug		r8;
+	}						rp;
+	struct sockaddr_hci				ha;
+	socklen_t					halen;
+	int						s, rval;
+
+	if (di == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	s = bt_devopen(di->devname);
+	if (s < 0)
+		return (-1);
+
+	rval = -1;
+
+	halen = sizeof(ha);
+	if (getsockname(s, (struct sockaddr *) &ha, &halen) < 0)
+		goto bad;
+	strlcpy(di->devname, ha.hci_node, sizeof(di->devname));
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &rp.r0, sizeof(rp.r0)) < 0)
+		goto bad;
+	di->state = rp.r0.state;
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &rp.r1, sizeof(rp.r1)) < 0)
+		goto bad;
+	bdaddr_copy(&di->bdaddr, &rp.r1.bdaddr);
+	
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &rp.r2, sizeof(rp.r2)) < 0)
+		goto bad;
+	memcpy(di->features, rp.r2.features, sizeof(di->features));
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &rp.r3, sizeof(rp.r3)) < 0)
+		goto bad;
+	di->cmd_free = rp.r3.buffer.cmd_free;
+	di->sco_size = rp.r3.buffer.sco_size;
+	di->sco_pkts = rp.r3.buffer.sco_pkts;
+	di->sco_free = rp.r3.buffer.sco_free;
+	di->acl_size = rp.r3.buffer.acl_size;
+	di->acl_pkts = rp.r3.buffer.acl_pkts;
+	di->acl_free = rp.r3.buffer.acl_free;
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &rp.r4, sizeof(rp.r4)) < 0)
+		goto bad;
+	di->cmd_sent = rp.r4.stat.cmd_sent;
+	di->evnt_recv = rp.r4.stat.evnt_recv;
+	di->acl_recv = rp.r4.stat.acl_recv;
+	di->acl_sent = rp.r4.stat.acl_sent;
+	di->sco_recv = rp.r4.stat.sco_recv;
+	di->sco_sent = rp.r4.stat.sco_sent;
+	di->bytes_recv = rp.r4.stat.bytes_recv;
+	di->bytes_sent = rp.r4.stat.bytes_sent;
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK,
+			&rp.r5, sizeof(rp.r5)) < 0)
+		goto bad;
+	di->link_policy_info = rp.r5.policy_mask;
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK,
+			&rp.r6, sizeof(rp.r6)) < 0)
+		goto bad;
+	di->packet_type_info = rp.r6.packet_mask;
+
+	 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH,
+			&rp.r7, sizeof(rp.r7)) < 0)
+		goto bad;
+	di->role_switch_info = rp.r7.role_switch;
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &rp.r8, sizeof(rp.r8)) < 0)
+		goto bad;
+	di->debug = rp.r8.debug;
+
+	rval = 0;
+bad:
+	bt_devclose(s);
+
+	return (rval);
+}
+
+int
+bt_devenum(bt_devenum_cb_t cb, void *arg)
+{
+	struct ng_btsocket_hci_raw_node_list_names	rp;
+	struct bt_devinfo				di;
+	struct sockaddr_hci				ha;
+	int						s, i, count;
+
+	rp.num_names = HCI_DEVMAX;
+	rp.names = (struct nodeinfo *) calloc(rp.num_names,
+						sizeof(struct nodeinfo));
+	if (rp.names == NULL) {
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	memset(&ha, 0, sizeof(ha));
+	ha.hci_len = sizeof(ha);
+	ha.hci_family = AF_BLUETOOTH;
+	ha.hci_node[0] = 'x';
+
+	s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
+	if (s < 0) {
+		free(rp.names);
+
+		return (-1);
+	}
+
+	if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 ||
+	    connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 ||
+	    ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &rp, sizeof(rp)) < 0) {
+		close(s);
+		free(rp.names);
+
+		return (-1);
+	}
+
+	for (count = 0, i = 0; i < rp.num_names; i ++) {
+		strlcpy(di.devname, rp.names[i].name, sizeof(di.devname));
+		if (bt_devinfo(&di) < 0)
+			continue;
+
+		count ++;
+
+		if (cb == NULL)
+			continue;
+
+		strlcpy(ha.hci_node, rp.names[i].name, sizeof(ha.hci_node));
+		if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 ||
+		    connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0)
+			continue;
+
+		if ((*cb)(s, &di, arg) > 0)
+			break;
+	}
+
+	close (s);
+	free(rp.names);
+
+	return (count);
+}
+
+static int
+bt_devany_cb(int s, struct bt_devinfo const *di, void *xdevname)
+{
+	strlcpy((char *) xdevname, di->devname, HCI_DEVNAME_SIZE);
+	return (1);
+}
+
+static char *
+bt_dev2node(char const *devname, char *nodename, int nnlen)
+{
+	static char const *	 bt_dev_prefix[] = {
+		"btccc",	/* 3Com Bluetooth PC-CARD */
+		"h4",		/* UART/serial Bluetooth devices */
+		"ubt",		/* Bluetooth USB devices */
+		NULL		/* should be last */
+	};
+
+	static char		_nodename[HCI_DEVNAME_SIZE];
+	char const		**p;
+	char			*ep;
+	int			plen, unit;
+
+	if (nodename == NULL) {
+		nodename = _nodename;
+		nnlen = HCI_DEVNAME_SIZE;
+	}
+
+	for (p = bt_dev_prefix; *p != NULL; p ++) {
+		plen = strlen(*p);
+		if (strncmp(devname, *p, plen) != 0)
+			continue;
+
+		unit = strtoul(devname + plen, &ep, 10);
+		if (*ep != '\0' &&
+		    strcmp(ep, "hci") != 0 &&
+		    strcmp(ep, "l2cap") != 0)
+			return (NULL);	/* can't make sense of device name */
+
+		snprintf(nodename, nnlen, "%s%uhci", *p, unit);
+
+		return (nodename);
+	}
+
+	return (NULL);
+}
+
diff --git a/lib/libsdp/Makefile b/lib/libsdp/Makefile
index 31a290cd38..e16a81e6f1 100644
--- a/lib/libsdp/Makefile
+++ b/lib/libsdp/Makefile
@@ -1,31 +1,27 @@
-# $NetBSD: Makefile,v 1.2 2007/05/28 12:06:21 tls Exp $
-# $FreeBSD: src/lib/libsdp/Makefile,v 1.4 2005/07/22 17:19:03 kensmith Exp $
-
-SYSDIR= ${.CURDIR}/../../sys/
+# $Id: Makefile,v 1.2 2003/09/07 20:34:19 max Exp $
+# $FreeBSD: head/lib/libsdp/Makefile 195767 2009-07-19 17:25:24Z kensmith $
 
 LIB=		sdp
-SHLIB_MAJOR=	2
 MAN=		sdp.3
+
 WARNS?=		2
+CFLAGS+=	-I${.CURDIR}
+
+SHLIB_MAJOR=	4
 
 SRCS=		search.c service.c session.c util.c
 INCS=		sdp.h
-INCSDIR=	/usr/include
-
-CFLAGS+=	-I${.CURDIR} -I${SYSDIR}
 
 MLINKS+=	sdp.3 SDP_GET8.3
 MLINKS+=	sdp.3 SDP_GET16.3
 MLINKS+=	sdp.3 SDP_GET32.3
 MLINKS+=	sdp.3 SDP_GET64.3
 MLINKS+=	sdp.3 SDP_GET128.3
-MLINKS+=	sdp.3 SDP_GET_UUID128.3
 MLINKS+=	sdp.3 SDP_PUT8.3
 MLINKS+=	sdp.3 SDP_PUT16.3
 MLINKS+=	sdp.3 SDP_PUT32.3
 MLINKS+=	sdp.3 SDP_PUT64.3
 MLINKS+=	sdp.3 SDP_PUT128.3
-MLINKS+=	sdp.3 SDP_PUT_UUID128.3
 MLINKS+=	sdp.3 sdp_open.3
 MLINKS+=	sdp.3 sdp_open_local.3
 MLINKS+=	sdp.3 sdp_close.3
diff --git a/lib/libsdp/sdp-int.h b/lib/libsdp/sdp-int.h
index 84b6e01cc2..f6f8bd89d0 100644
--- a/lib/libsdp/sdp-int.h
+++ b/lib/libsdp/sdp-int.h
@@ -1,6 +1,3 @@
-/* $NetBSD: sdp-int.h,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
-/* $DragonFly: src/lib/libsdp/sdp-int.h,v 1.1 2008/01/03 11:47:53 hasso Exp $ */
-
 /*
  * sdp-int.h
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: sdp-int.h,v 1.1 2006/06/19 15:44:36 gdamore Exp $
- * $FreeBSD: src/lib/libsdp/sdp-int.h,v 1.2 2004/01/09 18:19:12 emax Exp $
+ * $Id: sdp-int.h,v 1.1 2003/09/01 23:01:07 max Exp $
+ * $FreeBSD: head/lib/libsdp/sdp-int.h 124305 2004-01-09 18:19:12Z emax $
  */
 
 #ifndef _SDP_INT_H_
@@ -62,3 +59,4 @@ typedef struct sdp_session *	sdp_session_p;
 __END_DECLS
 
 #endif /* ndef _SDP_INT_H_ */
+
diff --git a/lib/libsdp/sdp.3 b/lib/libsdp/sdp.3
index 70fe137874..72aab5f5d7 100644
--- a/lib/libsdp/sdp.3
+++ b/lib/libsdp/sdp.3
@@ -1,5 +1,3 @@
-.\" $NetBSD: sdp.3,v 1.1 2006/06/19 15:44:36 gdamore Exp $
-.\"
 .\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
 .\" All rights reserved.
 .\"
@@ -24,8 +22,8 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $Id: sdp.3,v 1.1 2006/06/19 15:44:36 gdamore Exp $
-.\" $FreeBSD: src/lib/libsdp/sdp.3,v 1.10 2005/06/15 19:04:04 ru Exp $
+.\" $Id: sdp.3,v 1.1 2003/09/07 20:34:19 max Exp $
+.\" $FreeBSD: head/lib/libsdp/sdp.3 267773 2014-06-23 08:23:05Z bapt $
 .\"
 .Dd April 6, 2018
 .Dt SDP 3
@@ -87,7 +85,7 @@
 .Fn sdp_uuid2desc "uint16_t uuid"
 .Ft int32_t
 .Fo sdp_register_service
-.Fa "void *xss" "uint16_t uuid" "bdaddr_t *bdaddr" "uint8_t *data"
+.Fa "void *xss" "uint16_t uuid" "bdaddr_p const bdaddr" "uint8_t const *data"
 .Fa "uint32_t datalen" "uint32_t *handle"
 .Fc
 .Ft int32_t
@@ -144,7 +142,7 @@ function should point to a source BD_ADDR.
 If source BD_ADDR is
 .Dv NULL
 then source address
-.Dv BDADDR_ANY
+.Dv NG_HCI_BDADDR_ANY
 is used.
 The
 .Fa r
@@ -154,7 +152,7 @@ function should point to a
 .Pf non- Dv NULL
 remote BD_ADDR.
 Remote BD_ADDR cannot be
-.Dv BDADDR_ANY .
+.Dv NG_HCI_BDADDR_ANY .
 The
 .Fn sdp_open_local
 function takes path to the control socket and opens a connection to a local
@@ -272,7 +270,7 @@ Note: attributes are returned in the order they appear in the Service Search
 Attribute Response.
 SDP server could return several attributes for the same record.
 In this case the order of the attributes will be: all attributes for the first
-records, then all attributes for the secord record etc.
+records, then all attributes for the second record etc.
 .Pp
 The
 .Fn sdp_attr2desc
@@ -301,7 +299,7 @@ with
 If
 .Fa bdaddr
 is set to
-.Dv BDADDR_ANY
+.Dv NG_HCI_BDADDR_ANY
 then the service will be advertised to any remote devices that queries for it.
 The
 .Fa data
@@ -370,7 +368,7 @@ sdp_attr_t     proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer };
 
 /* Obtain/set remote BDADDR here */
 
-if ((ss = sdp_open(BDADDR_ANY, remote)) == NULL)
+if ((ss = sdp_open(NG_HCI_BDADDR_ANY, remote)) == NULL)
         /* exit ENOMEM */
 if (sdp_error(ss) != 0)
         /* exit sdp_error(ss) */
@@ -406,20 +404,10 @@ The caller is expected to call
 .Fn sdp_error
 to find out more about error.
 .Sh SEE ALSO
-.Xr sdpquery 1 ,
+.Xr bluetooth 3 ,
 .Xr strerror 3 ,
-.Xr bluetooth 4 ,
+.Xr sdpcontrol 8 ,
 .Xr sdpd 8
-.Sh HISTORY
-.Nm libsdp
-first appeared in
-.Fx ,
-was ported to
-.Nx 4.0
-by
-.An Iain Hibbert
-and imported into
-.Dx 1.11 .
 .Sh AUTHORS
 .An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
 .Sh BUGS
diff --git a/lib/libsdp/sdp.h b/lib/libsdp/sdp.h
index 1778a6d60b..c9f1127314 100644
--- a/lib/libsdp/sdp.h
+++ b/lib/libsdp/sdp.h
@@ -1,35 +1,3 @@
-/* $NetBSD: sdp.h,v 1.2 2006/08/17 20:13:31 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
 /*
  * sdp.h
  *
@@ -57,17 +25,13 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: sdp.h,v 1.2 2006/08/17 20:13:31 plunky Exp $
- * $FreeBSD: src/lib/libsdp/sdp.h,v 1.5 2005/05/27 19:11:33 emax Exp $
+ * $Id: sdp.h,v 1.3 2003/09/05 00:33:59 max Exp $
+ * $FreeBSD: head/lib/libsdp/sdp.h 226426 2011-10-16 08:45:16Z ed $
  */
 
 #ifndef _SDP_H_
 #define _SDP_H_
 
-#include <stdint.h>
-#include <string.h>
-#include <netbt/bluetooth.h>
-
 __BEGIN_DECLS
 
 /*
@@ -104,7 +68,7 @@ __BEGIN_DECLS
 /* Boolean */
 #define SDP_DATA_BOOL					0x28
 
-/*
+/* 
  * Data element sequence.
  * A data element whose data field is a sequence of data elements
  */
@@ -114,10 +78,10 @@ __BEGIN_DECLS
 
 /*
  * Data element alternative.
- * A data element whose data field is a sequence of data elements from
+ * A data element whose data field is a sequence of data elements from 
  * which one data element is to be selected.
  */
-#define SDP_DATA_ALT8					0x3D
+#define SDP_DATA_ALT8					0x3D 
 #define SDP_DATA_ALT16					0x3E
 #define SDP_DATA_ALT32					0x3F
 
@@ -127,7 +91,7 @@ __BEGIN_DECLS
 #define SDP_DATA_URL32					0x47
 
 /*
- * Protocols UUID (short) http://www.bluetoothsig.org/assigned-numbers/sdp.htm
+ * Protocols UUID (short) https://www.bluetooth.org/assigned-numbers/service_discovery.php
  * BASE UUID 00000000-0000-1000-8000-00805F9B34FB
  */
 
@@ -155,7 +119,7 @@ __BEGIN_DECLS
 #define SDP_UUID_PROTOCOL_L2CAP				0x0100
 
 /*
- * Service class IDs http://www.bluetoothsig.org/assigned-numbers/sdp.htm
+ * Service class IDs https://www.bluetooth.org/assigned-numbers/service_discovery.php
  */
 
 #define SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER	0x1000
@@ -206,6 +170,9 @@ __BEGIN_DECLS
 #define SDP_SERVICE_CLASS_UDI_TA			0x112B
 #define SDP_SERVICE_CLASS_AUDIO_VIDEO			0x112C
 #define SDP_SERVICE_CLASS_SIM_ACCESS			0x112D
+#define SDP_SERVICE_CLASS_PHONEBOOK_ACCESS_PCE		0x112E
+#define SDP_SERVICE_CLASS_PHONEBOOK_ACCESS_PSE		0x112F
+#define SDP_SERVICE_CLASS_PHONEBOOK_ACCESS		0x1130
 #define SDP_SERVICE_CLASS_PNP_INFORMATION		0x1200
 #define SDP_SERVICE_CLASS_GENERIC_NETWORKING		0x1201
 #define SDP_SERVICE_CLASS_GENERIC_FILE_TRANSFER		0x1202
@@ -216,10 +183,13 @@ __BEGIN_DECLS
 #define SDP_SERVICE_CLASS_ESDP_UPNP_IP_PAN		0x1300
 #define SDP_SERVICE_CLASS_ESDP_UPNP_IP_LAP		0x1301
 #define SDP_SERVICE_CLASS_ESDP_UPNP_L2CAP		0x1302
+#define SDP_SERVICE_CLASS_VIDEO_SOURCE			0x1303
+#define SDP_SERVICE_CLASS_VIDEO_SINK			0x1304
+#define SDP_SERVICE_CLASS_VIDEO_DISTRIBUTION		0x1305
 
 /*
  * Universal attribute definitions (page 366) and
- * http://www.bluetoothsig.org/assigned-numbers/sdp.htm
+ * https://www.bluetooth.org/assigned-numbers/service_discovery.php
  */
 
 #define SDP_ATTR_RANGE(lo, hi) \
@@ -266,10 +236,11 @@ __BEGIN_DECLS
 #define SDP_ATTR_SUPPORTED_FEATURES			0x0311
 #define SDP_ATTR_SUPPORTED_FUNCTIONS			0x0312
 #define SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY		0x0313
+#define SDP_ATTR_SUPPORTED_REPOSITORIES			0x0314
 
 /*
- * The offset must be added to the attribute ID base (contained in the
- * LANGUAGE_BASE_ATTRIBUTE_ID_LIST attribute) in order to compute the
+ * The offset must be added to the attribute ID base (contained in the 
+ * LANGUAGE_BASE_ATTRIBUTE_ID_LIST attribute) in order to compute the 
  * attribute ID for these attributes.
  */
 
@@ -340,114 +311,215 @@ typedef struct sdp_attr *	sdp_attr_p;
  *****************************************************************************/
 
 /* Inline versions of get/put byte/short/long. Pointer is advanced */
-#define SDP_GET8(b, cp)		do {			\
-	(b) = *(const uint8_t *)(cp);			\
-	(cp) += sizeof(uint8_t);			\
-} while (/* CONSTCOND */0)
-
-#define SDP_GET16(s, cp)	do {			\
-	(s) = be16dec(cp);				\
-	(cp) += sizeof(uint16_t);			\
-} while (/* CONSTCOND */0)
-
-#define SDP_GET32(l, cp)	do {			\
-	(l) = be32dec(cp);				\
-	(cp) += sizeof(uint32_t);			\
-} while (/* CONSTCOND */0)
-
-#define SDP_GET64(l, cp)	do {			\
-	(l) = be64dec(cp);				\
-	(cp) += sizeof(uint64_t);			\
-} while (/* CONSTCOND */0)
+#define SDP_GET8(b, cp) { \
+	const uint8_t *t_cp = (const uint8_t *)(cp); \
+	(b) = *t_cp; \
+	(cp) ++; \
+}
+
+#define SDP_GET16(s, cp) { \
+	const uint8_t *t_cp = (const uint8_t *)(cp); \
+	(s) = ((uint16_t)t_cp[0] << 8) \
+	    | ((uint16_t)t_cp[1]) \
+	    ; \
+	(cp) += 2; \
+}
+
+#define SDP_GET32(l, cp) { \
+	const uint8_t *t_cp = (const uint8_t *)(cp); \
+	(l) = ((uint32_t)t_cp[0] << 24) \
+	    | ((uint32_t)t_cp[1] << 16) \
+	    | ((uint32_t)t_cp[2] << 8) \
+	    | ((uint32_t)t_cp[3]) \
+	    ; \
+	(cp) += 4; \
+}
+
+#define SDP_GET64(l, cp) { \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	(l) = ((uint64_t)t_cp[0] << 56) \
+	    | ((uint64_t)t_cp[1] << 48) \
+	    | ((uint64_t)t_cp[2] << 40) \
+	    | ((uint64_t)t_cp[3] << 32) \
+	    | ((uint64_t)t_cp[4] << 24) \
+	    | ((uint64_t)t_cp[5] << 16) \
+	    | ((uint64_t)t_cp[6] << 8) \
+	    | ((uint64_t)t_cp[7]) \
+	    ; \
+	(cp) += 8; \
+}
 
 #if BYTE_ORDER == LITTLE_ENDIAN
-#define SDP_GET128(l, cp)	do {			\
-	const uint8_t *t_cp = (const uint8_t *)(cp);	\
-	(l)->b[15] = *t_cp++;				\
-	(l)->b[14] = *t_cp++;				\
-	(l)->b[13] = *t_cp++;				\
-	(l)->b[12] = *t_cp++;				\
-	(l)->b[11] = *t_cp++;				\
-	(l)->b[10] = *t_cp++;				\
-	(l)->b[9]  = *t_cp++;				\
-	(l)->b[8]  = *t_cp++;				\
-	(l)->b[7]  = *t_cp++;				\
-	(l)->b[6]  = *t_cp++;				\
-	(l)->b[5]  = *t_cp++;				\
-	(l)->b[4]  = *t_cp++;				\
-	(l)->b[3]  = *t_cp++;				\
-	(l)->b[2]  = *t_cp++;				\
-	(l)->b[1]  = *t_cp++;				\
-	(l)->b[0]  = *t_cp++;				\
-	(cp) += 16;					\
-} while (/* CONSTCOND */0)
-
-#define SDP_GET_UUID128(l, cp)	do {			\
-	memcpy(&((l)->b), (cp), 16);			\
-	(cp) += 16;					\
-} while (/* CONSTCOND */0)
+#define SDP_GET128(l, cp) { \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	(l)->b[15] = *t_cp++; \
+	(l)->b[14] = *t_cp++; \
+	(l)->b[13] = *t_cp++; \
+	(l)->b[12] = *t_cp++; \
+	(l)->b[11] = *t_cp++; \
+	(l)->b[10] = *t_cp++; \
+	(l)->b[9]  = *t_cp++; \
+	(l)->b[8]  = *t_cp++; \
+	(l)->b[7]  = *t_cp++; \
+	(l)->b[6]  = *t_cp++; \
+	(l)->b[5]  = *t_cp++; \
+	(l)->b[4]  = *t_cp++; \
+	(l)->b[3]  = *t_cp++; \
+	(l)->b[2]  = *t_cp++; \
+	(l)->b[1]  = *t_cp++; \
+	(l)->b[0]  = *t_cp++; \
+	(cp) += 16; \
+}
+
+#define SDP_GET_UUID128(l, cp) { \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	(l)->b[0]  = *t_cp++; \
+	(l)->b[1]  = *t_cp++; \
+	(l)->b[2]  = *t_cp++; \
+	(l)->b[3]  = *t_cp++; \
+	(l)->b[4]  = *t_cp++; \
+	(l)->b[5]  = *t_cp++; \
+	(l)->b[6]  = *t_cp++; \
+	(l)->b[7]  = *t_cp++; \
+	(l)->b[8]  = *t_cp++; \
+	(l)->b[9]  = *t_cp++; \
+	(l)->b[10] = *t_cp++; \
+	(l)->b[11] = *t_cp++; \
+	(l)->b[12] = *t_cp++; \
+	(l)->b[13] = *t_cp++; \
+	(l)->b[14] = *t_cp++; \
+	(l)->b[15] = *t_cp++; \
+	(cp) += 16; \
+}
 #elif BYTE_ORDER == BIG_ENDIAN
-#define SDP_GET128(l, cp)	do {			\
-	memcpy(&((l)->b), (cp), 16);			\
-	(cp) += 16;					\
-} while (/* CONSTCOND */0)
+#define SDP_GET128(l, cp) { \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	(l)->b[0]  = *t_cp++; \
+	(l)->b[1]  = *t_cp++; \
+	(l)->b[2]  = *t_cp++; \
+	(l)->b[3]  = *t_cp++; \
+	(l)->b[4]  = *t_cp++; \
+	(l)->b[5]  = *t_cp++; \
+	(l)->b[6]  = *t_cp++; \
+	(l)->b[7]  = *t_cp++; \
+	(l)->b[8]  = *t_cp++; \
+	(l)->b[9]  = *t_cp++; \
+	(l)->b[10] = *t_cp++; \
+	(l)->b[11] = *t_cp++; \
+	(l)->b[12] = *t_cp++; \
+	(l)->b[13] = *t_cp++; \
+	(l)->b[14] = *t_cp++; \
+	(l)->b[15] = *t_cp++; \
+	(cp) += 16; \
+}
 
 #define	SDP_GET_UUID128(l, cp)	SDP_GET128(l, cp)
 #else
 #error	"Unsupported BYTE_ORDER"
 #endif /* BYTE_ORDER */
 
-#define SDP_PUT8(b, cp)		do {			\
-	*(uint8_t *)(cp) = (b);				\
-	(cp) += sizeof(uint8_t);			\
-} while (/* CONSTCOND */0)
-
-#define SDP_PUT16(s, cp)	do {			\
-	be16enc((cp), (s));				\
-	(cp) += sizeof(uint16_t);			\
-} while (/* CONSTCOND */0)
-
-#define SDP_PUT32(s, cp)	do {			\
-	be32enc((cp), (s));				\
-	(cp) += sizeof(uint32_t);			\
-} while (/* CONSTCOND */0)
-
-#define SDP_PUT64(s, cp)	do {			\
-	be64enc((cp), (s));				\
-	(cp) += sizeof(uint64_t);			\
-} while (/* CONSTCOND */0)
+#define SDP_PUT8(b, cp) { \
+	register uint8_t t_b = (uint8_t)(b); \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	*t_cp = t_b; \
+	(cp) ++; \
+}
+
+#define SDP_PUT16(s, cp) { \
+	register uint16_t t_s = (uint16_t)(s); \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	*t_cp++ = t_s >> 8; \
+	*t_cp   = t_s; \
+	(cp) += 2; \
+}
+
+#define SDP_PUT32(l, cp) { \
+	register uint32_t t_l = (uint32_t)(l); \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	*t_cp++ = t_l >> 24; \
+	*t_cp++ = t_l >> 16; \
+	*t_cp++ = t_l >> 8; \
+	*t_cp   = t_l; \
+	(cp) += 4; \
+}
+
+#define SDP_PUT64(l, cp) { \
+	register uint64_t t_l = (uint64_t)(l); \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	*t_cp++ = t_l >> 56; \
+	*t_cp++ = t_l >> 48; \
+	*t_cp++ = t_l >> 40; \
+	*t_cp++ = t_l >> 32; \
+	*t_cp++ = t_l >> 24; \
+	*t_cp++ = t_l >> 16; \
+	*t_cp++ = t_l >> 8; \
+	*t_cp   = t_l; \
+	(cp) += 8; \
+}
 
 #if BYTE_ORDER == LITTLE_ENDIAN
-#define SDP_PUT128(l, cp)	do {			\
-	const uint8_t *t_cp = (const uint8_t *)(cp);	\
-	*t_cp++ = (l)->b[15];				\
-	*t_cp++ = (l)->b[14];				\
-	*t_cp++ = (l)->b[13];				\
-	*t_cp++ = (l)->b[12];				\
-	*t_cp++ = (l)->b[11];				\
-	*t_cp++ = (l)->b[10];				\
-	*t_cp++ = (l)->b[9];				\
-	*t_cp++ = (l)->b[8];				\
-	*t_cp++ = (l)->b[7];				\
-	*t_cp++ = (l)->b[6];				\
-	*t_cp++ = (l)->b[5];				\
-	*t_cp++ = (l)->b[4];				\
-	*t_cp++ = (l)->b[3];				\
-	*t_cp++ = (l)->b[2];				\
-	*t_cp++ = (l)->b[1];				\
-	*t_cp   = (l)->b[0];				\
-	(cp) += 16;					\
-} while (/* CONSTCOND */0)
-
-#define SDP_PUT_UUID128(l, cp)	do {			\
-	memcpy((cp), &((l)->b), 16);			\
-	(cp) += 16;					\
-} while (/* CONSTCOND */0)
+#define SDP_PUT128(l, cp) { \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	*t_cp++ = (l)->b[15]; \
+	*t_cp++ = (l)->b[14]; \
+	*t_cp++ = (l)->b[13]; \
+	*t_cp++ = (l)->b[12]; \
+	*t_cp++ = (l)->b[11]; \
+	*t_cp++ = (l)->b[10]; \
+	*t_cp++ = (l)->b[9];  \
+	*t_cp++ = (l)->b[8];  \
+	*t_cp++ = (l)->b[7];  \
+	*t_cp++ = (l)->b[6];  \
+	*t_cp++ = (l)->b[5];  \
+	*t_cp++ = (l)->b[4];  \
+	*t_cp++ = (l)->b[3];  \
+	*t_cp++ = (l)->b[2];  \
+	*t_cp++ = (l)->b[1];  \
+	*t_cp   = (l)->b[0];  \
+	(cp) += 16; \
+}
+
+#define SDP_PUT_UUID128(l, cp) { \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	*t_cp++ = (l)->b[0];  \
+	*t_cp++ = (l)->b[1];  \
+	*t_cp++ = (l)->b[2];  \
+	*t_cp++ = (l)->b[3];  \
+	*t_cp++ = (l)->b[4];  \
+	*t_cp++ = (l)->b[5];  \
+	*t_cp++ = (l)->b[6];  \
+	*t_cp++ = (l)->b[7];  \
+	*t_cp++ = (l)->b[8];  \
+	*t_cp++ = (l)->b[9];  \
+	*t_cp++ = (l)->b[10]; \
+	*t_cp++ = (l)->b[11]; \
+	*t_cp++ = (l)->b[12]; \
+	*t_cp++ = (l)->b[13]; \
+	*t_cp++ = (l)->b[14]; \
+	*t_cp   = (l)->b[15]; \
+	(cp) += 16; \
+}
 #elif BYTE_ORDER == BIG_ENDIAN
-#define SDP_PUT128(l, cp)	do {			\
-	memcpy((cp), &((l)->b), 16);			\
-	(cp) += 16;					\
-} while (/* CONSTCOND */0)
+#define SDP_PUT128(l, cp) { \
+	register uint8_t *t_cp = (uint8_t *)(cp); \
+	*t_cp++ = (l)->b[0];  \
+	*t_cp++ = (l)->b[1];  \
+	*t_cp++ = (l)->b[2];  \
+	*t_cp++ = (l)->b[3];  \
+	*t_cp++ = (l)->b[4];  \
+	*t_cp++ = (l)->b[5];  \
+	*t_cp++ = (l)->b[6];  \
+	*t_cp++ = (l)->b[7];  \
+	*t_cp++ = (l)->b[8];  \
+	*t_cp++ = (l)->b[9];  \
+	*t_cp++ = (l)->b[10]; \
+	*t_cp++ = (l)->b[11]; \
+	*t_cp++ = (l)->b[12]; \
+	*t_cp++ = (l)->b[13]; \
+	*t_cp++ = (l)->b[14]; \
+	*t_cp   = (l)->b[15]; \
+	(cp) += 16; \
+}
 
 #define SDP_PUT_UUID128(l, cp)	SDP_PUT128(l, cp)
 #else
@@ -464,9 +536,9 @@ int32_t            sdp_search     (void *xs,
                                    uint32_t alen, uint32_t const *ap,
                                    uint32_t vlen, sdp_attr_t *vp);
 
-char const *       sdp_attr2desc  (uint16_t attr);
-char const *       sdp_uuid2desc  (uint16_t uuid);
-void               sdp_print      (uint32_t level, uint8_t *start,
+char const *	   sdp_attr2desc  (uint16_t attr);
+char const *	   sdp_uuid2desc  (uint16_t uuid);
+void               sdp_print      (uint32_t level, uint8_t const *start,
                                    uint8_t const *end);
 
 /******************************************************************************
@@ -484,8 +556,8 @@ void               sdp_print      (uint32_t level, uint8_t *start,
  * and depend on the request.
  *
  * SDP_PDU_SERVICE_REGISTER_REQUEST
- *	pdu_header_t	hdr;
- *	uint16_t	uuid;	service class UUID (network byte order)
+ * 	pdu_header_t	hdr;
+ *	u_int16_t	uuid;	service class UUID (network byte order)
  *	bdaddr_t	bdaddr;	local BD_ADDR (or ANY)
  *	profile data[pdu->len - sizeof(uuid) - sizeof(bdaddr)]
  *
@@ -494,14 +566,14 @@ void               sdp_print      (uint32_t level, uint8_t *start,
  *
  * SDP_PDU_SERVICE_UNREGISTER_REQUEST
  *	pdu_header_t	hdr;
- *	uint32_t	record_handle;	(network byte order)
- *
+ *	u_int32_t	record_handle;	(network byte order)
+ * 
  * no additional data in response.
  *
  *
  * SDP_PDU_SERVICE_CHANGE_REQUEST
- *	pdu_header_t	hdr;
- *	uint32_t	record_handle;	(network byte order)
+ * 	pdu_header_t	hdr;
+ *	u_int32_t	record_handle;	(network byte order)
  *	profile data[pdu->len - sizeof(record_handle)]
  *
  * no additional data in response.
@@ -528,22 +600,6 @@ struct sdp_ftrn_profile
 typedef struct sdp_ftrn_profile		sdp_ftrn_profile_t;
 typedef struct sdp_ftrn_profile *	sdp_ftrn_profile_p;
 
-struct sdp_hset_profile
-{
-	uint8_t server_channel;
-	uint8_t	reserved[3];
-};
-typedef struct sdp_hset_profile		sdp_hset_profile_t;
-typedef struct sdp_hset_profile *	sdp_hset_profile_p;
-
-struct sdp_hf_profile
-{
-	uint8_t server_channel;
-	uint16_t supported_features;
-};
-typedef struct sdp_hf_profile		sdp_hf_profile_t;
-typedef struct sdp_hf_profile *		sdp_hf_profile_p;
-
 /* Keep this in sync with sdp_opush_profile */
 struct sdp_irmc_profile
 {
@@ -591,13 +647,48 @@ struct sdp_sp_profile
 typedef struct sdp_sp_profile	sdp_sp_profile_t;
 typedef struct sdp_sp_profile *	sdp_sp_profile_p;
 
+struct sdp_nap_profile
+{
+	uint8_t		reserved;
+	uint8_t		load_factor;
+	uint16_t	psm;			/* HBO */
+	uint16_t	security_description;	/* HBO */
+	uint16_t	net_access_type;	/* HBO */
+	uint32_t	max_net_access_rate;	/* HBO */
+};
+typedef struct sdp_nap_profile		sdp_nap_profile_t;
+typedef struct sdp_nap_profile *	sdp_nap_profile_p;
+
+struct sdp_gn_profile
+{	
+	uint8_t		reserved;
+	uint8_t		load_factor;
+	uint16_t	psm;			/* HBO */
+	uint16_t	security_description;	/* HBO */
+	uint16_t	reserved2;
+};
+typedef struct sdp_gn_profile		sdp_gn_profile_t;
+typedef struct sdp_gn_profile *		sdp_gn_profile_p;
+
+struct sdp_panu_profile
+{
+	uint8_t		reserved;
+	uint8_t		load_factor;
+	uint16_t	psm;			/* HBO */
+	uint16_t	security_description;	/* HBO */
+	uint16_t	reserved2;
+};
+typedef struct sdp_panu_profile		sdp_panu_profile_t;
+typedef struct sdp_panu_profile *	sdp_panu_profile_p;
+
 int32_t	sdp_register_service	(void *xss, uint16_t uuid,
-				 bdaddr_t *bdaddr, uint8_t *data,
+				 bdaddr_p const bdaddr, uint8_t const *data,
 				 uint32_t datalen, uint32_t *handle);
 int32_t	sdp_unregister_service	(void *xss, uint32_t handle);
 int32_t	sdp_change_service	(void *xss, uint32_t handle,
-				 uint8_t *data, uint32_t datalen);
+				 uint8_t const *data, uint32_t datalen);
 
 __END_DECLS
 
 #endif /* ndef _SDP_H_ */
+
diff --git a/lib/libsdp/search.c b/lib/libsdp/search.c
index b586f2fc64..803eb8f0e6 100644
--- a/lib/libsdp/search.c
+++ b/lib/libsdp/search.c
@@ -1,6 +1,3 @@
-/* $NetBSD: search.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
-/* $DragonFly: src/lib/libsdp/search.c,v 1.1 2008/01/03 11:47:53 hasso Exp $ */
-
 /*
  * search.c
  *
@@ -13,10 +10,10 @@
  * 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
+ *    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
+ * 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
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: search.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
- * $FreeBSD: src/lib/libsdp/search.c,v 1.7 2004/12/09 18:57:12 emax Exp $
+ * $Id: search.c,v 1.2 2003/09/04 22:12:13 max Exp $
+ * $FreeBSD: head/lib/libsdp/search.c 173673 2007-11-16 15:13:12Z emax $
  */
 
 #include <sys/uio.h>
@@ -104,7 +101,7 @@ sdp_search(void *xss,
 		ss->error = ENOBUFS;
 		return (-1);
 	}
-
+		
 	/* Put ServiceSearchPattern */
 	SDP_PUT8(SDP_DATA_SEQ16, req);
 	SDP_PUT16(plen, req);
@@ -207,15 +204,18 @@ sdp_search(void *xss,
 			return (-1);
 		}
 
+		rsp += xpdu.len;
+		ss->tid ++;
+
 		/* Save continuation state (if any) */
-		ss->cslen = rsp[xpdu.len];
+		ss->cslen = rsp[0];
 		if (ss->cslen > 0) {
 			if (ss->cslen > sizeof(ss->cs)) {
 				ss->error = ENOBUFS;
 				return (-1);
 			}
 
-			memcpy(ss->cs, rsp + xpdu.len + 1, ss->cslen);
+			memcpy(ss->cs, rsp + 1, ss->cslen);
 
 			/*
 			 * Ensure that we always have ss->imtu bytes
@@ -227,7 +227,7 @@ sdp_search(void *xss,
 
 				size = ss->rsp_e - ss->rsp + ss->imtu;
 				offset = rsp - ss->rsp;
-
+		
 				rsp_tmp = realloc(ss->rsp, size);
 				if (rsp_tmp == NULL) {
 					ss->error = ENOMEM;
@@ -239,9 +239,6 @@ sdp_search(void *xss,
 				rsp = ss->rsp + offset;
 			}
 		}
-
-		rsp += xpdu.len;
-		ss->tid ++;
 	} while (ss->cslen > 0);
 
 	/*
@@ -249,12 +246,12 @@ sdp_search(void *xss,
 	 * we must populate attribute values into vp array. At this point
 	 * ss->rsp points to the beginning of the response and rsp points
 	 * to the end of the response.
-	 *
+	 * 
 	 * From Bluetooth v1.1 spec page 364
-	 *
+	 * 
 	 * The AttributeLists is a data element sequence where each element
 	 * in turn is a data element sequence representing an attribute list.
-	 * Each attribute list contains attribute IDs and attribute values
+	 * Each attribute list contains attribute IDs and attribute values 
 	 * from one service record. The first element in each attribute list
 	 * contains the attribute ID of the first attribute to be returned for
 	 * that service record. The second element in each attribute list
@@ -263,9 +260,9 @@ sdp_search(void *xss,
 	 * and value pairs. Only attributes that have non-null values within
 	 * the service record and whose attribute IDs were specified in the
 	 * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists
-	 * Neither an attribute ID nor attribute value is placed in
-	 * AttributeLists for attributes in the service record that have no
-	 * value. Within each attribute list, the attributes are listed in
+	 * Neither an attribute ID nor attribute value is placed in 
+	 * AttributeLists for attributes in the service record that have no 
+	 * value. Within each attribute list, the attributes are listed in 
 	 * ascending order of attribute ID value.
 	 */
 
@@ -421,3 +418,4 @@ sdp_search(void *xss,
 
 	return (0);
 }
+
diff --git a/lib/libsdp/service.c b/lib/libsdp/service.c
index 9def829748..0d9bcf8bf0 100644
--- a/lib/libsdp/service.c
+++ b/lib/libsdp/service.c
@@ -1,36 +1,3 @@
-/* $NetBSD: service.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
-/* $DragonFly: src/lib/libsdp/service.c,v 1.1 2008/01/03 11:47:53 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
 /*
  * service.c
  *
@@ -43,10 +10,10 @@
  * 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
+ *    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
+ * 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
@@ -58,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: service.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
- * $FreeBSD: src/lib/libsdp/service.c,v 1.1 2004/01/20 20:48:25 emax Exp $
+ * $Id: service.c,v 1.1 2004/01/13 19:32:36 max Exp $
+ * $FreeBSD: head/lib/libsdp/service.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <sys/uio.h>
@@ -76,8 +43,8 @@
 static int32_t sdp_receive_error_pdu(sdp_session_p ss);
 
 int32_t
-sdp_register_service(void *xss, uint16_t uuid, bdaddr_t *bdaddr,
-		uint8_t *data, uint32_t datalen, uint32_t *handle)
+sdp_register_service(void *xss, uint16_t uuid, bdaddr_p const bdaddr,
+		uint8_t const *data, uint32_t datalen, uint32_t *handle)
 {
 	sdp_session_p	ss = (sdp_session_p) xss;
 	struct iovec	iov[4];
@@ -155,12 +122,10 @@ sdp_unregister_service(void *xss, uint32_t handle)
 		ss->error = EINVAL;
 		return (-1);
 	}
-#if 0
 	if (sizeof(pdu) + sizeof(handle) > SDP_LOCAL_MTU) {
 		ss->error = EMSGSIZE;
 		return (-1);
 	}
-#endif
 
 	pdu.pid = SDP_PDU_SERVICE_UNREGISTER_REQUEST;
 	pdu.tid = htons(++ss->tid);
@@ -188,7 +153,7 @@ sdp_unregister_service(void *xss, uint32_t handle)
 
 int32_t
 sdp_change_service(void *xss, uint32_t handle,
-		uint8_t *data, uint32_t datalen)
+		uint8_t const *data, uint32_t datalen)
 {
 	sdp_session_p	ss = (sdp_session_p) xss;
 	struct iovec	iov[3];
@@ -236,12 +201,12 @@ sdp_change_service(void *xss, uint32_t handle,
 static int32_t
 sdp_receive_error_pdu(sdp_session_p ss)
 {
-	sdp_pdu_t	pdu;
+	sdp_pdu_p	pdu;
 	int32_t		len;
 	uint16_t	error;
 
 	do {
-		len = read(ss->s, ss->rsp, (size_t)(ss->rsp_e - ss->rsp));
+		len = read(ss->s, ss->rsp, ss->rsp_e - ss->rsp);
 	} while (len < 0 && errno == EINTR);
 
 	if (len < 0) {
@@ -249,13 +214,12 @@ sdp_receive_error_pdu(sdp_session_p ss)
 		return (-1);
 	}
 
-	memcpy(&pdu, ss->rsp, sizeof(pdu));
-	pdu.tid = ntohs(pdu.tid);
-	pdu.len = ntohs(pdu.len);
-	memcpy(ss->rsp, &pdu, sizeof(pdu));
+	pdu = (sdp_pdu_p) ss->rsp;
+	pdu->tid = ntohs(pdu->tid);
+	pdu->len = ntohs(pdu->len);
 
-	if (pdu.pid != SDP_PDU_ERROR_RESPONSE || pdu.tid != ss->tid ||
-	    pdu.len < 2 || pdu.len != len - sizeof(pdu)) {
+	if (pdu->pid != SDP_PDU_ERROR_RESPONSE || pdu->tid != ss->tid ||
+	    pdu->len < 2 || pdu->len != len - sizeof(*pdu)) {
 		ss->error = EIO;
 		return (-1);
 	}
@@ -270,3 +234,4 @@ sdp_receive_error_pdu(sdp_session_p ss)
 
 	return (len);
 }
+
diff --git a/lib/libsdp/session.c b/lib/libsdp/session.c
index 1c3c402c24..e301e91bab 100644
--- a/lib/libsdp/session.c
+++ b/lib/libsdp/session.c
@@ -1,36 +1,3 @@
-/* $NetBSD: session.c,v 1.2 2007/04/07 21:08:46 plunky Exp $ */
-/* $DragonFly: src/lib/libsdp/session.c,v 1.1 2008/01/03 11:47:53 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
 /*
  * session.c
  *
@@ -43,10 +10,10 @@
  * 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
+ *    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
+ * 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
@@ -58,12 +25,10 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: session.c,v 1.2 2007/04/07 21:08:46 plunky Exp $
- * $FreeBSD: src/lib/libsdp/session.c,v 1.3 2004/01/09 22:44:28 emax Exp $
+ * $Id: session.c,v 1.2 2003/09/04 22:12:13 max Exp $
+ * $FreeBSD: head/lib/libsdp/session.c 124317 2004-01-09 22:44:28Z emax $
  */
 
-#include <sys/types.h>
-#include <sys/un.h>
 #include <bluetooth.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -77,8 +42,7 @@ void *
 sdp_open(bdaddr_t const *l, bdaddr_t const *r)
 {
 	sdp_session_p		ss = NULL;
-	struct sockaddr_bt	sa;
-	struct linger		li;
+	struct sockaddr_l2cap	sa;
 	socklen_t		size;
 
 	if ((ss = calloc(1, sizeof(*ss))) == NULL)
@@ -89,53 +53,45 @@ sdp_open(bdaddr_t const *l, bdaddr_t const *r)
 		goto fail;
 	}
 
-	ss->s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+	ss->s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
 	if (ss->s < 0) {
 		ss->error = errno;
 		goto fail;
 	}
 
-	memset(&li, 0, sizeof(li));
-	li.l_onoff = 1;
-	li.l_linger = 5;
-	if (setsockopt(ss->s, SOL_SOCKET, SO_LINGER, &li, sizeof(li)) < 0) {
-		ss->error = errno;
-		goto fail;
-	}
-
-	memset(&sa, 0, sizeof(sa));
-	sa.bt_len = sizeof(sa);
-	sa.bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&sa.bt_bdaddr, l);
-	if (bind(ss->s, (void *) &sa, sizeof(sa)) < 0) {
+	sa.l2cap_len = sizeof(sa);
+	sa.l2cap_family = AF_BLUETOOTH;
+	sa.l2cap_psm = 0;
+	memcpy(&sa.l2cap_bdaddr, l, sizeof(sa.l2cap_bdaddr));
+	if (bind(ss->s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
 		ss->error = errno;
 		goto fail;
 	}
 
-	sa.bt_psm = L2CAP_PSM_SDP;
-	bdaddr_copy(&sa.bt_bdaddr, r);
-	if (connect(ss->s, (void *) &sa, sizeof(sa)) < 0) {
+	sa.l2cap_psm = htole16(NG_L2CAP_PSM_SDP);
+	memcpy(&sa.l2cap_bdaddr, r, sizeof(sa.l2cap_bdaddr));
+	if (connect(ss->s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
 		ss->error = errno;
 		goto fail;
 	}
 
 	size = sizeof(ss->omtu);
-	if (getsockopt(ss->s, BTPROTO_L2CAP, SO_L2CAP_OMTU, &ss->omtu, &size) < 0) {
+	if (getsockopt(ss->s, SOL_L2CAP, SO_L2CAP_OMTU, &ss->omtu, &size) < 0) {
 		ss->error = errno;
 		goto fail;
 	}
-	if ((ss->req = malloc((size_t)ss->omtu)) == NULL) {
+	if ((ss->req = malloc(ss->omtu)) == NULL) {
 		ss->error = ENOMEM;
 		goto fail;
 	}
 	ss->req_e = ss->req + ss->omtu;
 
 	size = sizeof(ss->imtu);
-	if (getsockopt(ss->s, BTPROTO_L2CAP, SO_L2CAP_IMTU, &ss->imtu, &size) < 0) {
+	if (getsockopt(ss->s, SOL_L2CAP, SO_L2CAP_IMTU, &ss->imtu, &size) < 0) {
 		ss->error = errno;
 		goto fail;
 	}
-	if ((ss->rsp = malloc((size_t)ss->imtu)) == NULL) {
+	if ((ss->rsp = malloc(ss->imtu)) == NULL) {
 		ss->error = ENOMEM;
 		goto fail;
 	}
@@ -154,7 +110,7 @@ sdp_open_local(char const *control)
 	if ((ss = calloc(1, sizeof(*ss))) == NULL)
 		goto fail;
 
-	ss->s = socket(PF_LOCAL, SOCK_STREAM, 0);
+	ss->s = socket(PF_UNIX, SOCK_STREAM, 0);
 	if (ss->s < 0) {
 		ss->error = errno;
 		goto fail;
@@ -164,10 +120,10 @@ sdp_open_local(char const *control)
 		control = SDP_LOCAL_PATH;
 
 	sa.sun_len = sizeof(sa);
-	sa.sun_family = AF_LOCAL;
+	sa.sun_family = AF_UNIX;
 	strlcpy(sa.sun_path, control, sizeof(sa.sun_path));
 
-	if (connect(ss->s, (void *) &sa, sizeof(sa)) < 0) {
+	if (connect(ss->s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
 		ss->error = errno;
 		goto fail;
 	}
@@ -175,13 +131,13 @@ sdp_open_local(char const *control)
 	ss->flags |= SDP_SESSION_LOCAL;
 	ss->imtu = ss->omtu = SDP_LOCAL_MTU;
 
-	if ((ss->req = malloc((size_t)ss->omtu)) == NULL) {
+	if ((ss->req = malloc(ss->omtu)) == NULL) {
 		ss->error = ENOMEM;
 		goto fail;
 	}
 	ss->req_e = ss->req + ss->omtu;
 
-	if ((ss->rsp = malloc((size_t)ss->imtu)) == NULL) {
+	if ((ss->rsp = malloc(ss->imtu)) == NULL) {
 		ss->error = ENOMEM;
 		goto fail;
 	}
diff --git a/lib/libsdp/util.c b/lib/libsdp/util.c
index 3a62c52b6e..410fcc5aa9 100644
--- a/lib/libsdp/util.c
+++ b/lib/libsdp/util.c
@@ -1,36 +1,3 @@
-/* $NetBSD: util.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
-/* $DragonFly: src/lib/libsdp/util.c,v 1.2 2008/09/30 16:57:05 swildner Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
 /*
  * util.c
  *
@@ -43,10 +10,10 @@
  * 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
+ *    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
+ * 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
@@ -58,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: util.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
- * $FreeBSD: src/lib/libsdp/util.c,v 1.5 2005/05/27 19:11:33 emax Exp $
+ * $Id: util.c,v 1.5 2003/09/08 02:29:35 max Exp $
+ * $FreeBSD: head/lib/libsdp/util.c 161662 2006-08-26 23:16:35Z markus $
  */
 
 #include <netinet/in.h>
@@ -150,6 +117,9 @@ static sdp_attr_desc_t	sdp_uuids_desc[] = {
 { SDP_SERVICE_CLASS_UDI_TA, "UDI TA", },
 { SDP_SERVICE_CLASS_AUDIO_VIDEO, "Audio/Video", },
 { SDP_SERVICE_CLASS_SIM_ACCESS, "SIM Access", },
+{ SDP_SERVICE_CLASS_PHONEBOOK_ACCESS_PCE, "Phonebook Access - PCE", },
+{ SDP_SERVICE_CLASS_PHONEBOOK_ACCESS_PSE, "Phonebook Access - PSE", },
+{ SDP_SERVICE_CLASS_PHONEBOOK_ACCESS, "Phonebook Access", },
 { SDP_SERVICE_CLASS_PNP_INFORMATION, "PNP Information", },
 { SDP_SERVICE_CLASS_GENERIC_NETWORKING, "Generic Networking", },
 { SDP_SERVICE_CLASS_GENERIC_FILE_TRANSFER, "Generic File Transfer", },
@@ -160,6 +130,9 @@ static sdp_attr_desc_t	sdp_uuids_desc[] = {
 { SDP_SERVICE_CLASS_ESDP_UPNP_IP_PAN, "ESDP UPNP IP PAN", },
 { SDP_SERVICE_CLASS_ESDP_UPNP_IP_LAP, "ESDP UPNP IP LAP", },
 { SDP_SERVICE_CLASS_ESDP_UPNP_L2CAP, "ESDP UPNP L2CAP", },
+{ SDP_SERVICE_CLASS_VIDEO_SOURCE, "Video Source", },
+{ SDP_SERVICE_CLASS_VIDEO_SINK, "Video Sink", },
+{ SDP_SERVICE_CLASS_VIDEO_DISTRIBUTION, "Video Distribution", },
 { 0xffff, NULL, }
 };
 
@@ -193,7 +166,7 @@ static sdp_attr_desc_t	sdp_attrs_desc[] = {
   },
 { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
   "Bluetooh Profile Descriptor List",
-  },
+  }, 
 { SDP_ATTR_DOCUMENTATION_URL,
   "Documentation URL",
   },
@@ -274,13 +247,16 @@ static sdp_attr_desc_t	sdp_attrs_desc[] = {
 { SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY,
   "Total Imaging Data Capacity",
   },
+{ SDP_ATTR_SUPPORTED_REPOSITORIES,
+  "Supported Repositories",
+  },
 { 0xffff, NULL, }
 };
 
 char const *
 sdp_attr2desc(uint16_t attr)
 {
-	sdp_attr_desc_p	a = sdp_attrs_desc;
+	register sdp_attr_desc_p	a = sdp_attrs_desc;
 
 	for (; a->desc != NULL; a++)
 		if (attr == a->attr)
@@ -292,7 +268,7 @@ sdp_attr2desc(uint16_t attr)
 char const *
 sdp_uuid2desc(uint16_t uuid)
 {
-	sdp_attr_desc_p	a = sdp_uuids_desc;
+	register sdp_attr_desc_p	a = sdp_uuids_desc;
 
 	for (; a->desc != NULL; a++)
 		if (uuid == a->attr)
@@ -302,7 +278,7 @@ sdp_uuid2desc(uint16_t uuid)
 }
 
 void
-sdp_print(uint32_t level, uint8_t *start, uint8_t const *end)
+sdp_print(uint32_t level, uint8_t const *start, uint8_t const *end)
 {
 	union {
 		int8_t		int8;
@@ -352,37 +328,22 @@ sdp_print(uint32_t level, uint8_t *start, uint8_t const *end)
 		case SDP_DATA_UINT128:
 		case SDP_DATA_INT128:
 			SDP_GET128(&value.int128, start);
-			printf("u/int128 0x"
-				"%2.2x%2.2x%2.2x%2.2x"
-				"%2.2x%2.2x%2.2x%2.2x"
-				"%2.2x%2.2x%2.2x%2.2x"
-				"%2.2x%2.2x%2.2x%2.2x\n",
-				value.int128.b[ 0], value.int128.b[ 1],
-				value.int128.b[ 2], value.int128.b[ 3],
-				value.int128.b[ 4], value.int128.b[ 5],
-				value.int128.b[ 6], value.int128.b[ 7],
-				value.int128.b[ 8], value.int128.b[ 9],
-				value.int128.b[10], value.int128.b[11],
-				value.int128.b[12], value.int128.b[13],
-				value.int128.b[14], value.int128.b[15]);
+			printf("u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
+				*(uint32_t *)&value.int128.b[0],
+				*(uint32_t *)&value.int128.b[4],
+				*(uint32_t *)&value.int128.b[8],
+				*(uint32_t *)&value.int128.b[12]);
 			break;
 
 		case SDP_DATA_UUID128:
 			SDP_GET_UUID128(&value.int128, start);
-			printf("uuid128 0x"
-				"%2.2x%2.2x%2.2x%2.2x-"
-				"%2.2x%2.2x-"
-				"%2.2x%2.2x-"
-				"%2.2x%2.2x-"
-				"%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
-				value.int128.b[ 0], value.int128.b[ 1],
-				value.int128.b[ 2], value.int128.b[ 3],
-				value.int128.b[ 4], value.int128.b[ 5],
-				value.int128.b[ 6], value.int128.b[ 7],
-				value.int128.b[ 8], value.int128.b[ 9],
-				value.int128.b[10], value.int128.b[11],
-				value.int128.b[12], value.int128.b[13],
-				value.int128.b[14], value.int128.b[15]);
+			printf("uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
+				ntohl(*(uint32_t *)&value.int128.b[0]),
+				ntohs(*(uint16_t *)&value.int128.b[4]),
+				ntohs(*(uint16_t *)&value.int128.b[6]),
+				ntohs(*(uint16_t *)&value.int128.b[8]),
+				ntohs(*(uint16_t *)&value.int128.b[10]),
+				ntohl(*(uint32_t *)&value.int128.b[12]));
 			break;
 
 		case SDP_DATA_INT8:
@@ -401,7 +362,7 @@ sdp_print(uint32_t level, uint8_t *start, uint8_t const *end)
 			SDP_GET64(value.int64, start);
 			printf("int64 %ju\n", value.int64);
 			break;
-
+	
 		case SDP_DATA_UUID16:
 			SDP_GET16(value.uint16, start);
 			printf("uuid16 %#4.4x - %s\n", value.uint16,
@@ -486,10 +447,11 @@ sdp_print(uint32_t level, uint8_t *start, uint8_t const *end)
 			printf("url32 %*.*s\n", value.uint32, value.uint32, start);
 			start += value.uint32;
 			break;
-
+	
 		default:
 			printf("unknown data type: %#02x\n", *start ++);
 			break;
 		}
 	}
 }
+
diff --git a/share/examples/etc/README.examples b/share/examples/etc/README.examples
index d6405793e1..72e6eba3b4 100644
--- a/share/examples/etc/README.examples
+++ b/share/examples/etc/README.examples
@@ -68,6 +68,7 @@ sysctl.conf	- kernel state defaults
 syslog.conf	- configuration file for syslogd(8)
 ttys		- defines port configuration for init(8)
 defaults/	- directory containing default configuration files
+defaults/bluetooth.device.conf	- default Bluetooth device configuration file
 defaults/compilers.conf	- default configuration for non-base compilers
 defaults/devfs.conf	- default rule file for devfs(5)
 defaults/make.conf	- system build default information
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 93c8c48603..08128cfaba 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -49,7 +49,6 @@ MAN=	aac.4 \
 	bge.4 \
 	bktr.4 \
 	blackhole.4 \
-	bluetooth.4 \
 	bnx.4 \
 	bpf.4 \
 	bridge.4 \
@@ -334,7 +333,6 @@ MAN=	aac.4 \
 	ubsa.4 \
 	ubsec.4 \
 	ubser.4 \
-	ubt.4 \
 	uchcom.4 \
 	ucycom.4 \
 	ucom.4 \
diff --git a/share/man/man4/bluetooth.4 b/share/man/man4/bluetooth.4
deleted file mode 100644
index 7caadade40..0000000000
--- a/share/man/man4/bluetooth.4
+++ /dev/null
@@ -1,392 +0,0 @@
-.\" $NetBSD: bluetooth.4,v 1.9 2007/11/28 20:16:12 plunky Exp $
-.\" $DragonFly: src/share/man/man4/bluetooth.4,v 1.4 2008/04/14 08:17:09 swildner Exp $
-.\"
-.\" Copyright (c) 2006 Itronix Inc.
-.\" All rights reserved.
-.\"
-.\" Written by Iain Hibbert for Itronix Inc.
-.\"
-.\" 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. The name of Itronix Inc. may not be used to endorse
-.\"    or promote products derived from this software without specific
-.\"    prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
-.\"
-.\"
-.Dd December 28, 2007
-.Dt BLUETOOTH 4
-.Os
-.Sh NAME
-.Nm bluetooth
-.Nd Bluetooth Protocol Family
-.Sh SYNOPSIS
-.In netbt/bluetooth.h
-.In netbt/hci.h
-.In netbt/l2cap.h
-.In netbt/rfcomm.h
-.Sh DESCRIPTION
-The
-.Tn Bluetooth
-Protocol Family
-.Sh ADDRESSING
-Bluetooth Protocol Family sockets all use a
-.Ar sockaddr_bt
-structure which contains a Bluetooth Device Address (BDADDR).
-This consists of a six byte string in least significant byte
-first order.
-.Bd -literal -offset indent
-struct sockaddr_bt {
-	uint8_t		bt_len;
-	sa_family_t	bt_family;
-	bdaddr_t	bt_bdaddr;
-	uint16_t	bt_psm;
-	uint8_t		bt_channel;
-};
-.Ed
-.Pp
-The local address used by the socket can be set with
-.Xr bind 2 .
-.Sh PROTOCOLS
-Protocols included are:
-.Bl -tag -width XX
-.It Cm BTPROTO_HCI
-This gives raw access to the Host Controller Interface of local devices
-using the HCI protocol as described in the Bluetooth Core Specification.
-Any user may open an HCI socket but there are limitations on what
-unprivileged users can send and receive. The local address specified by
-.Xr bind 2
-may be used to select the device that the socket will receive packets from. If
-.Dv BDADDR_ANY
-is specified then the socket will receive packets from all
-devices on the system.
-.Xr connect 2
-may be used to create connections such that packets sent with
-.Xr send 2
-will be delivered to the specified device, otherwise
-.Xr sendto 2
-should be used.
-.Pp
-The
-.Ar bt_psm
-and
-.Ar bt_channel
-fields in the sockaddr_bt structure are ignored by HCI protocol code
-and should be set to zero.
-.Pp
-HCI socket options:
-.Bl -tag -width XX
-.It Dv SO_HCI_EVT_FILTER Op Ar struct hci_filter
-This filter controls which events will be received at the socket. See
-.In netbt/hci.h
-for available events. By default, Command_Complete and Command_Status
-events only are enabled.
-.It Dv SO_HCI_PKT_FILTER Op Ar struct hci_filter
-This filter controls the type of packets that will be received at the
-socket. By default, Event packets only are enabled.
-.It Dv SO_HCI_DIRECTION Op Ar int
-When set, this enables control messages on packets received at the socket
-indicating the direction of travel of the packet.
-.El
-.Pp
-HCI
-.Xr sysctl 8
-controls:
-.Bl -tag -width XXX
-.It Va net.bluetooth.hci.sendspace
-Default send buffer size for HCI sockets.
-.It Va net.bluetooth.hci.recvspace
-Default receive buffer size for HCI sockets
-.It Va net.bluetooth.hci.acl_expiry
-If set, this is the time in seconds after which unused ACL data connections
-will be expired. If zero, connections will not be closed.
-.It Va net.bluetooth.hci.memo_expiry
-Time, in seconds, that the system will keep records of Bluetooth devices
-in the vicinity after an Inquiry Response packet has been received. This
-information is used for routing purposes.
-.It Va net.bluetooth.hci.eventq_max
-The maximum number of packets on the low level Event queue.
-.It Va net.bluetooth.hci.aclrxq_max
-The maximum number of packets on the low level ACL queue.
-.It Va net.bluetooth.hci.scorxq_max
-The maximum number of packets on the low level SCO queue.
-.El
-.It Cm BTPROTO_L2CAP
-L2CAP sockets give sequential packet access over channels to other Bluetooth
-devices and make use of the
-.Ar bt_psm
-field in the
-.Ar sockaddr_bt
-structure to select the Protocol/Service Multiplexer to specify when making
-connections.
-.Pp
-L2CAP socket options:
-.Bl -tag -width XXX
-.It Dv SO_L2CAP_IMTU Op Ar uint16_t
-Incoming MTU
-.It Dv SO_L2CAP_OMTU Op Ar uint16_t
-Outgoing MTU (read-only)
-.It Dv SO_L2CAP_LM Op Ar int
-Link Mode.
-The following bits may be set:
-.Pp
-.Bl -tag -compact -width ".Dv L2CAP_LM_ENCRYPT"
-.It Dv L2CAP_LM_AUTH
-Request authentication
-.Pq pairing .
-.It Dv L2CAP_LM_ENCRYPT
-Request encryption
-.Pq includes auth .
-.It Dv L2CAP_LM_SECURE
-Request secured link
-.Pq encryption, plus change link key .
-.El
-.Pp
-Link mode settings will be applied to the baseband link during L2CAP
-connection establishment.
-If the L2CAP connection is already established,
-.Er EINPROGRESS
-may be returned, and it is not possible to guarantee that data already queued
-.Pq from either end
-will not be delivered.
-If the mode change fails, the L2CAP connection will be aborted.
-.El
-.Pp
-L2CAP
-.Xr sysctl 8
-controls:
-.Bl -tag -width XXX
-.It Va net.bluetooth.l2cap.sendspace
-Default send buffer size for L2CAP sockets.
-.It Va net.bluetooth.l2cap.recvspace
-Default receive buffer size for L2CAP sockets.
-.It Va net.bluetooth.l2cap.rtx
-Response Timeout eXpiry for L2CAP signals.
-.It Va net.bluetooth.l2cap.ertx
-Extended Response Timeout eXpiry for L2CAP signals.
-.El
-.It Cm BTPROTO_RFCOMM
-RFCOMM sockets provide streamed data over Bluetooth connection and make use of the
-.Ar bt_psm ,
-and
-.Ar bt_channel
-fields in the
-.Ar sockaddr_bt
-structure.
-The channel number must be between 1 and 30 inclusive except that if the
-special value
-.Dv RFCOMM_CHANNEL_ANY
-is bound, when the
-.Xr listen 2
-call is made, the first unused channel for the relevant bdaddr will be
-allocated and may be discovered using the
-.Xr getsockname 2
-call.
-If no PSM is specified, a default value of
-.Dv L2CAP_PSM_RFCOMM
-(0x0003) will be used.
-.Pp
-RFCOMM socket options:
-.Bl -tag -width XXX
-.It Dv SO_RFCOMM_MTU Op Ar uint16_t
-Maximum Frame Size to use for this link.
-.It Dv SO_RFCOMM_LM Op Ar int
-Link Mode.
-The following bits may be set at any time:
-.Pp
-.Bl -tag -compact -width ".Dv RFCOMM_LM_ENCRYPT"
-.It Dv RFCOMM_LM_AUTH
-Request authentication
-.Pq pairing .
-.It Dv RFCOMM_LM_ENCRYPT
-Request encryption
-.Pq includes auth .
-.It Dv RFCOMM_LM_SECURE
-Request secured link
-.Pq encryption, plus change link key .
-.El
-.Pp
-Link mode settings will be applied to the baseband link during RFCOMM
-connection establishment.
-If the RFCOMM connection is already established,
-.Er EINPROGRESS
-may be returned, and it is not possible to guarantee that data already queued
-.Pq from either end
-will not be delivered.
-If the mode change fails, the RFCOMM connection will be aborted.
-.El
-.Pp
-RFCOMM
-.Xr sysctl 8
-controls:
-.Bl -tag -width XXX
-.It Va net.bluetooth.rfcomm.sendspace
-Default send buffer size for RFCOMM sockets.
-.It Va net.bluetooth.rfcomm.recvspace
-Default receive buffer size for RFCOMM sockets.
-.It Va net.bluetooth.rfcomm.default_mtu
-Maximum Frame Size (N1)
-.It Va net.bluetooth.rfcomm.ack_timeout
-Acknowledgement Timer (T1)
-.It Va net.bluetooth.rfcomm.mcc_timeout
-Response Timer for Multiplexer Control Channel (T2)
-.El
-.It Cm BTPROTO_SCO
-SCO sockets provide sequential packet access to time sensitive data
-channels over Bluetooth connections, typically used for audio data.
-.Pp
-SCO socket options:
-.Bl -tag -width XXX
-.It Dv SO_SCO_MTU Op Ar uint16_t
-Maximum packet size for use on this link.
-This is read-only and will be set by the protocol code when a connection is made.
-Currently, due to limitations in the
-.Xr ubt 4
-driver, the SCO protocol code will only accept packets with
-exactly this size.
-.It Dv SO_SCO_HANDLE Op Ar uint16_t
-Connection handle for this link.
-This is read-only and provided for informational purposes only.
-.El
-.Pp
-SCO
-.Xr sysctl 8
-controls:
-.Bl -tag -width XXX
-.It Va net.bluetooth.sco.sendspace
-Default send buffer size for SCO sockets.
-.It Va net.bluetooth.sco.recvspace
-Default receive buffer size for SCO sockets.
-.El
-.El
-.Sh INFORMATION
-The following
-.Xr ioctl 2
-calls may be used to manipulate Bluetooth devices. The
-.Xr ioctl 2
-must be made on
-.Cm BTPROTO_HCI
-sockets. All of the requests take a
-.Ar btreq
-structure defined as follows as their parameter and unless otherwise
-specified, use the
-.Ar btr_name
-field to identify the device.
-.Bd -literal
-struct btreq {
-    char btr_name[HCI_DEVNAME_SIZE];	/* device name */
-
-    union {
-	struct {
-	    bdaddr_t btri_bdaddr;	/* device bdaddr */
-	    uint16_t btri_flags;	/* flags */
-	    uint16_t btri_num_cmd;	/* # of free cmd buffers */
-	    uint16_t btri_num_acl;	/* # of free ACL buffers */
-	    uint16_t btri_num_sco;	/* # of free SCO buffers */
-	    uint16_t btri_acl_mtu;	/* ACL mtu */
-	    uint16_t btri_sco_mtu;	/* SCO mtu */
-	    uint16_t btri_link_policy;	/* Link Policy */
-	    uint16_t btri_packet_type;	/* Packet Type */
-	} btri;
-	struct bt_stats btrs;   /* unit stats */
-    } btru;
-};
-
-#define btr_flags	btru.btri.btri_flags
-#define btr_bdaddr	btru.btri.btri_bdaddr
-#define btr_num_cmd	btru.btri.btri_num_cmd
-#define btr_num_acl	btru.btri.btri_num_acl
-#define btr_num_sco	btru.btri.btri_num_sco
-#define btr_acl_mtu	btru.btri.btri_acl_mtu
-#define btr_sco_mtu	btru.btri.btri_sco_mtu
-#define btr_link_policy btru.btri.btri_link_policy
-#define btr_packet_type btru.btri.btri_packet_type
-#define btr_stats	btru.btrs
-
-/* btr_flags */
-#define BTF_UP			(1\*[Lt]\*[Lt]0)	/* unit is up */
-#define BTF_RUNNING		(1\*[Lt]\*[Lt]1)	/* unit is running */
-#define BTF_XMIT_CMD		(1\*[Lt]\*[Lt]2)	/* transmitting CMD packets */
-#define BTF_XMIT_ACL		(1\*[Lt]\*[Lt]3)	/* transmitting ACL packets */
-#define BTF_XMIT_SCO		(1\*[Lt]\*[Lt]4)	/* transmitting SCO packets */
-#define BTF_INIT_BDADDR		(1\*[Lt]\*[Lt]5)	/* waiting for bdaddr */
-#define BTF_INIT_BUFFER_SIZE	(1\*[Lt]\*[Lt]6)	/* waiting for buffer size */
-#define BTF_INIT_FEATURES	(1\*[Lt]\*[Lt]7)	/* waiting for features */
-#define BTF_NOOP_ON_RESET	(1\*[Lt]\*[Lt]8)	/* wait for No-op on reset */
-#define BTF_INIT_COMMANDS	(1\*[Lt]\*[Lt]9)	/* waiting for supported commands */
-
-struct bt_stats {
-	uint32_t	err_tx;
-	uint32_t	err_rx;
-	uint32_t	cmd_tx;
-	uint32_t	evt_rx;
-	uint32_t	acl_tx;
-	uint32_t	acl_rx;
-	uint32_t	sco_tx;
-	uint32_t	sco_rx;
-	uint32_t	byte_tx;
-	uint32_t	byte_rx;
-};
-
-.Ed
-.Bl -tag -width SIOCGBTPOLICY
-.It Dv SIOCGBTINFO
-Get Bluetooth device Info. Given the device name, fill in the
-btreq structure including the address field for use with socket addressing
-as above.
-.It Dv SIOCGBTINFOA
-Get Bluetooth device Info from Address. Given the device address, fill in the
-btreq structure including the name field.
-.It Dv SIOCNBTINFO
-Next Bluetooth device Info . If name field is empty, the first device
-will be returned. Otherwise, the next device will be returned. Thus, you
-can cycle through all devices in the system.
-.It Dv SIOCSBTFLAGS
-Set Bluetooth device Flags. Not all flags are settable.
-.It Dv SIOCSBTPOLICY
-Set Bluetooth device Link Policy. Link Policy bits are defined in
-.In netbt/hci.h ,
-though you can only set bits that the device supports.
-.It Dv SIOCSBTPTYPE
-Set Bluetooth device Packet Types. You can only set packet types
-that the device supports.
-.It Dv SIOCGBTSTATS
-Read device statistics.
-.It Dv SIOCZBTSTATS
-Read device statistics, and zero them.
-.El
-.Pp
-Only the super-user may change device configurations.
-.Sh SEE ALSO
-.Xr bind 2 ,
-.Xr getsockname 2 ,
-.Xr bluetooth 3 ,
-.\".Xr bcsp 4 ,
-.\".Xr bt3c 4 ,
-.\".Xr btbc 4 ,
-.\".Xr btuart 4 ,
-.Xr ubt 4
-.Sh HISTORY
-The Bluetooth Protocol Stack was written for
-.Nx 4.0
-by
-.An Iain Hibbert
-under the sponsorship of Itronix, Inc and was imported into
-.Dx 1.11 .
diff --git a/share/man/man4/ng_bluetooth.4 b/share/man/man4/ng_bluetooth.4
new file mode 100644
index 0000000000..755fbd8eb2
--- /dev/null
+++ b/share/man/man4/ng_bluetooth.4
@@ -0,0 +1,112 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: ng_bluetooth.4,v 1.3 2003/05/21 19:37:35 max Exp $
+.\" $FreeBSD: head/share/man/man4/ng_bluetooth.4 267938 2014-06-26 21:46:14Z bapt $
+.\"
+.Dd November 9, 2002
+.Dt NG_BLUETOOTH 4
+.Os
+.Sh NAME
+.Nm ng_bluetooth
+.Nd placeholder for global Bluetooth variables
+.Sh SYNOPSIS
+.In sys/types.h
+.In netgraph/bluetooth/include/ng_bluetooth.h
+.Sh DESCRIPTION
+The
+.Nm
+module is a placeholder for global Bluetooth variables.
+All Bluetooth variables can be examined and changed via
+.Xr sysctl 8 .
+.Ss Bluetooth Variables
+Below is the description of default variables.
+Each Bluetooth module might add its own variables to the tree.
+.Bl -tag -width foo
+.It Va net.bluetooth.version
+A read-only integer variable that shows the current version of the
+Bluetooth stack.
+.It Va net.bluetooth.hci.command_timeout
+A read-write integer variable that controls the Host Controller Interface
+(HCI) command timeout (in seconds), i.e., how long the HCI layer will wait
+for the
+.Dv Command_Complete
+or
+.Dv Command_Status
+event from a Bluetooth device.
+.It Va net.bluetooth.hci.connection_timeout
+A read-write integer variable that controls the HCI connection timeout, i.e.\&
+how long the HCI layer will wait for the
+.Dv Connection_Complete
+event.
+Normally this should not be required as Bluetooth devices have
+connection timeout of their own and will send event back.
+This timeout
+is required to ensure that no connection will stall in case when the HCI
+transport layer is broken.
+Be careful when changing this variable.
+Make sure you understand what you are doing.
+.It Va net.bluetooth.hci.max_neighbor_age
+A read-write integer variable that controls time-to-live (in seconds) for
+entries in the HCI neighbor cache.
+Every time a Bluetooth device performs an
+.Dv Inquiry
+operation, the results will be put in cache.
+Later when a Bluetooth device
+establishes a baseband connection, it will try to find the matching entry in
+the cache and use it.
+This might speed up establishment of the baseband
+connection.
+.It Va net.bluetooth.l2cap.rtx_timeout
+A read-write integer variable that controls the Link Layer Control and
+Adaptation Protocol (L2CAP) Retransmission Timeout (RTX) (in seconds).
+Every time the L2CAP layer submits a control command, the RTX timeout is set.
+The value of the RTX timeout should be greater or equal to the value of
+the HCI connection timeout.
+Be careful when changing this variable.
+Make sure you understand what you are doing.
+.It Va net.bluetooth.l2cap.ertx_timeout
+A read-write integer variable that controls the L2CAP Extended Retransmission
+Timeout (ERTX) (in seconds).
+In some cases remote peer may respond with
+.Dv PENDING
+status to the L2CAP control command.
+In this case the L2CAP command timeout is reset to the ERTX timeout value.
+The value of the ERTX timeout should be
+greater or equal to the value of the RTX timeout.
+Be careful when changing this variable.
+Make sure you understand what you are doing.
+.El
+.Sh SEE ALSO
+.Xr ng_btsocket 4 ,
+.Xr ng_hci 4 ,
+.Xr ng_l2cap 4 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+module was implemented in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
diff --git a/share/man/man4/ng_bt3c.4 b/share/man/man4/ng_bt3c.4
new file mode 100644
index 0000000000..cf355532fb
--- /dev/null
+++ b/share/man/man4/ng_bt3c.4
@@ -0,0 +1,129 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: ng_bt3c.4,v 1.3 2003/09/14 23:28:51 max Exp $
+.\" $FreeBSD: head/share/man/man4/ng_bt3c.4 267938 2014-06-26 21:46:14Z bapt $
+.\"
+.Dd December 17, 2004
+.Dt NG_BT3C 4
+.Os
+.Sh NAME
+.Nm ng_bt3c
+.Nd Netgraph node type that is also a 3Com Bluetooth PC card driver
+.Sh SYNOPSIS
+.In sys/types.h
+.In netgraph/bluetooth/include/ng_bt3c.h
+.Sh DESCRIPTION
+The
+.Nm btccc
+node type is both a persistent Netgraph node type and a driver for the
+3Com Bluetooth PC card (3CRWB6096-HP).
+It implements a Bluetooth HCI
+UART transport layer as per chapter H4 of the Bluetooth Specification
+Book v1.1.
+A new node is created when the card is plugged.
+.Pp
+In order to use the card one
+.Em MUST
+download the firmware first.
+Due to copyright issues the firmware cannot be provided with this driver.
+The firmware can be obtained
+from the Windows driver package that can be downloaded from the 3Com web
+site at no charge.
+The firmware name is
+.Pa BT3CPCC.BIN .
+To load the firmware into the card, use
+.Xr bt3cfw 8 .
+I am using the original firmware that came with the card on CD-ROM.
+.Pp
+.Dl "MD5 (BT3CPCC.BIN) = 36170fda56ea9fdbf1702c966f8a97f1"
+.Pp
+The node has a single hook called
+.Dv hook .
+Incoming bytes received on the device are re-assembled into HCI frames
+(according to the length).
+Full HCI frames are sent out on the hook.
+HCI frames received on
+.Dv hook
+are transmitted out.
+No modification to the data is performed in either direction.
+.Sh HARDWARE
+The
+.Nm
+driver provides support for the 3Com/HP 3CRWB6096-A PCCARD bluetooth adapter.
+.Sh HOOKS
+This node type supports the following hooks:
+.Bl -tag -width ".Va hook"
+.It Va hook
+single HCI frame contained in single
+.Vt mbuf
+structure.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_BT3C_NODE_GET_STATE Pq Ic get_state
+Returns the current receiving state for the node.
+.It Dv NGM_BT3C_NODE_SET_DEBUG Pq Ic set_debug
+This command takes an integer argument and sets the current debug level
+for the node.
+.It Dv NGM_BT3C_NODE_GET_DEBUG Pq Ic get_debug
+Returns an integer containing the current debug level for the node.
+.It Dv NGM_BT3C_NODE_GET_QLEN Pq Ic get_qlen
+This command takes a parameter that specifies queue number and returns
+the current length of the queue for the node.
+.It Dv NGM_BT3C_NODE_SET_QLEN Pq Ic set_qlen
+This command takes two parameters that specify the queue number and
+the maximum length of the queue and sets the maximum length of the queue for
+the node.
+.It Dv NGM_BT3C_NODE_GET_STAT Pq Ic get_stat
+Returns various statistic information for the node, such as: number of
+bytes (frames) sent, number of bytes (frames) received and number of
+input (output) errors.
+.It Dv NGM_BT3C_NODE_RESET_STAT Pq Ic reset_stat
+Reset all statistic counters to zero.
+.It Dv NGM_BT3C_NODE_DOWNLOAD_FIRMWARE
+Download card firmware.
+.El
+.Sh SHUTDOWN
+This node shuts down when the corresponding card is un-plugged.
+.Sh SEE ALSO
+.Xr cardbus 4 ,
+.Xr netgraph 4 ,
+.Xr pccbb 4 ,
+.Xr pcic 4 ,
+.Xr pccard.conf 5 ,
+.Xr bt3cfw 8 ,
+.Xr ngctl 8
+.Sh HISTORY
+The
+.Nm btccc
+node type was implemented in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+The driver is based on information obtained from
+.An Jose Orlando Pereira Aq Mt jop@di.uminho.pt
+and disassembled the W2K driver.
diff --git a/share/man/man4/ng_btsocket.4 b/share/man/man4/ng_btsocket.4
new file mode 100644
index 0000000000..e38d8bbf1c
--- /dev/null
+++ b/share/man/man4/ng_btsocket.4
@@ -0,0 +1,354 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: ng_btsocket.4,v 1.7 2003/05/21 19:37:35 max Exp $
+.\" $FreeBSD: head/share/man/man4/ng_btsocket.4 267938 2014-06-26 21:46:14Z bapt $
+.\"
+.Dd November 13, 2012
+.Dt NG_BTSOCKET 4
+.Os
+.Sh NAME
+.Nm ng_btsocket
+.Nd Bluetooth sockets layer
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/socket.h
+.In sys/bitstring.h
+.In netgraph/bluetooth/include/ng_hci.h
+.In netgraph/bluetooth/include/ng_l2cap.h
+.In netgraph/bluetooth/include/ng_btsocket.h
+.Sh DESCRIPTION
+The
+.Nm
+module implements three Netgraph node types.
+Each type in its turn implements one protocol within
+.Dv PF_BLUETOOTH
+domain.
+.Sh Dv BLUETOOTH_PROTO_HCI Sh protocol
+.Ss Dv SOCK_RAW Ss HCI sockets
+Implemented by
+.Nm btsock_hci_raw
+Netgraph type.
+Raw HCI sockets allow sending of raw HCI command datagrams
+only to correspondents named in
+.Xr send 2
+calls.
+Raw HCI datagrams (HCI commands, events and data) are generally received with
+.Xr recvfrom 2 ,
+which returns the next datagram with its return address.
+Raw HCI sockets can also be used to control HCI nodes.
+.Pp
+The Bluetooth raw HCI socket address is defined as follows:
+.Bd -literal -offset indent
+/* Bluetooth version of struct sockaddr for raw HCI sockets */
+struct sockaddr_hci {
+        u_char	hci_len;      /* total length */
+        u_char	hci_family;   /* address family */
+	char	hci_node[32]; /* address (size == NG_NODESIZ ) */
+};
+.Ed
+.Pp
+Raw HCI sockets support a number of
+.Xr ioctl 2
+requests such as:
+.Bl -tag -width foo
+.It Dv SIOC_HCI_RAW_NODE_GET_STATE
+Returns current state for the HCI node.
+.It Dv SIOC_HCI_RAW_NODE_INIT
+Turn on
+.Dq inited
+bit for the HCI node.
+.It Dv SIOC_HCI_RAW_NODE_GET_DEBUG
+Returns current debug level for the HCI node.
+.It Dv SIOC_HCI_RAW_NODE_SET_DEBUG
+Sets current debug level for the HCI node.
+.It Dv SIOC_HCI_RAW_NODE_GET_BUFFER
+Returns current state of data buffers for the HCI node.
+.It Dv SIOC_HCI_RAW_NODE_GET_BDADDR
+Returns BD_ADDR for the HCI node.
+.It Dv SIOC_HCI_RAW_NODE_GET_FEATURES
+Returns the list of features supported by hardware for the HCI node.
+.It Dv SIOC_HCI_RAW_NODE_GET_STAT
+Returns various statistic counters for the HCI node.
+.It Dv SIOC_HCI_RAW_NODE_RESET_STAT
+Resets all statistic counters for the HCI node to zero.
+.It Dv SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE
+Remove all neighbor cache entries for the HCI node.
+.It Dv SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE
+Returns content of the neighbor cache for the HCI node.
+.It Dv SIOC_HCI_RAW_NODE_GET_CON_LIST
+Returns list of active baseband connections (i.e., ACL and SCO links) for
+the HCI node.
+.It SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK
+Returns current link policy settings mask for the HCI node.
+.It SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK
+Sets current link policy settings mask for the HCI node.
+.It SIOC_HCI_RAW_NODE_GET_PACKET_MASK
+Returns current packet mask for the HCI node.
+.It SIOC_HCI_RAW_NODE_SET_PACKET_MASK
+Sets current packet mask for the HCI node.
+.It SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH
+Returns current value of the role switch parameter for the HCI node.
+.It SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH
+Sets new value of the role switch parameter for the HCI node.
+.El
+.Pp
+The
+.Va net.bluetooth.hci.sockets.raw.ioctl_timeout
+variable, that can be examined and set via
+.Xr sysctl 8 ,
+controls the control request timeout (in seconds) for raw HCI sockets.
+.Pp
+Raw HCI sockets support filters.
+The application can filter certain HCI datagram types.
+For HCI event datagrams the application can set additional filter.
+The raw HCI socket filter defined as follows:
+.Bd -literal -offset indent
+/*
+ * Raw HCI socket filter.
+ *
+ * For packet mask use (1 << (HCI packet indicator - 1))
+ * For event mask use (1 << (Event - 1))
+ */
+
+struct ng_btsocket_hci_raw_filter {
+        bitstr_t bit_decl(packet_mask, 32);
+        bitstr_t bit_decl(event_mask, (NG_HCI_EVENT_MASK_SIZE * 8));
+};
+.Ed
+.Pp
+The
+.Dv SO_HCI_RAW_FILTER
+option defined at
+.Dv SOL_HCI_RAW
+level can be used to obtain via
+.Xr getsockopt 2
+or change via
+.Xr setsockopt 2
+raw HCI socket's filter.
+.Sh Dv BLUETOOTH_PROTO_L2CAP Sh protocol
+The Bluetooth L2CAP socket address is defined as follows:
+.Bd -literal -offset indent
+/* Bluetooth version of struct sockaddr for L2CAP sockets */
+struct sockaddr_l2cap {
+        u_char    l2cap_len;    /* total length */
+        u_char    l2cap_family; /* address family */
+        uint16_t  l2cap_psm;    /* Protocol/Service Multiplexor */
+        bdaddr_t  l2cap_bdaddr; /* address */
+};
+.Ed
+.Ss Dv SOCK_RAW Ss L2CAP sockets
+Implemented by
+.Nm btsock_l2c_raw
+Netgraph type.
+Raw L2CAP sockets do not provide access to raw L2CAP datagrams.
+These
+sockets used to control L2CAP nodes and to issue special L2CAP requests
+such as
+.Dv ECHO_REQUEST
+and
+.Dv GET_INFO
+request.
+.Pp
+Raw L2CAP sockets support number of
+.Xr ioctl 2
+requests such as:
+.Bl -tag -width foo
+.It Dv SIOC_L2CAP_NODE_GET_FLAGS
+Returns current state for the L2CAP node.
+.It Dv SIOC_L2CAP_NODE_GET_DEBUG
+Returns current debug level for the L2CAP node.
+.It Dv SIOC_L2CAP_NODE_SET_DEBUG
+Sets current debug level for the L2CAP node.
+.It Dv SIOC_L2CAP_NODE_GET_CON_LIST
+Returns list of active baseband connections (i.e., ACL links) for the L2CAP
+node.
+.It Dv SIOC_L2CAP_NODE_GET_CHAN_LIST
+Returns list of active channels for the L2CAP node.
+.It Dv SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO
+Returns current value of the auto disconnect timeout for the L2CAP node.
+.It Dv SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO
+Sets current value of the auto disconnect timeout for the L2CAP node.
+.It Dv SIOC_L2CAP_L2CA_PING
+Issues L2CAP
+.Dv ECHO_REQUEST .
+.It Dv SIOC_L2CAP_L2CA_GET_INFO
+Issues L2CAP
+.Dv GET_INFO
+request.
+.El
+.Pp
+The
+.Va net.bluetooth.l2cap.sockets.raw.ioctl_timeout
+variable, that can be examined and set via
+.Xr sysctl 8 ,
+controls the control request timeout (in seconds) for raw L2CAP sockets.
+.Ss Dv SOCK_SEQPACKET Ss L2CAP sockets
+Implemented by
+.Nm btsock_l2c
+Netgraph type.
+L2CAP sockets are either
+.Dq active
+or
+.Dq passive .
+Active sockets initiate connections to passive sockets.
+By default, L2CAP sockets are created active; to create a passive socket, the
+.Xr listen 2
+system call must be used after binding the socket with the
+.Xr bind 2
+system call.
+Only passive sockets may use the
+.Xr accept 2
+call to accept incoming connections.
+Only active sockets may use the
+.Xr connect 2
+call to initiate connections.
+.Pp
+L2CAP sockets support
+.Dq "wildcard addressing" .
+In this case, socket must be bound to
+.Dv NG_HCI_BDADDR_ANY
+address.
+Note that PSM (Protocol/Service Multiplexor) field is always required.
+Once a connection has been established, the socket's address is
+fixed by the peer entity's location.
+The address assigned to the socket is
+the address associated with the Bluetooth device through which packets are
+being transmitted and received, and PSM (Protocol/Service Multiplexor).
+.Pp
+L2CAP sockets support number of options defined at
+.Dv SOL_L2CAP
+level which can be set with
+.Xr setsockopt 2
+and tested with
+.Xr getsockopt 2 :
+.Bl -tag -width foo
+.It Dv SO_L2CAP_IMTU
+Get (set) maximum payload size the local socket is capable of accepting.
+.It Dv SO_L2CAP_OMTU
+Get maximum payload size the remote socket is capable of accepting.
+.It Dv SO_L2CAP_IFLOW
+Get incoming flow specification for the socket.
+.Bf -emphasis
+Not implemented.
+.Ef
+.It Dv SO_L2CAP_OFLOW
+Get (set) outgoing flow specification for the socket.
+.Bf -emphasis
+Not implemented.
+.Ef
+.It Dv SO_L2CAP_FLUSH
+Get (set) value of the flush timeout.
+.Bf -emphasis
+Not implemented.
+.Ef
+.El
+.Sh Dv BLUETOOTH_PROTO_RFCOMM Sh protocol
+The Bluetooth RFCOMM socket address is defined as follows:
+.Bd -literal -offset indent
+/* Bluetooth version of struct sockaddr for RFCOMM sockets */
+struct sockaddr_rfcomm {
+        u_char   rfcomm_len;     /* total length */
+        u_char   rfcomm_family;  /* address family */
+        bdaddr_t rfcomm_bdaddr;  /* address */
+        uint8_t  rfcomm_channel; /* channel */
+};
+.Ed
+.Ss Dv SOCK_STREAM Ss RFCOMM sockets
+Note that RFCOMM sockets do not have associated Netgraph node type.
+RFCOMM sockets are implemented as additional layer on top of L2CAP sockets.
+RFCOMM sockets are either
+.Dq active
+or
+.Dq passive .
+Active sockets initiate connections to passive sockets.
+By default, RFCOMM sockets are created active; to create a passive socket, the
+.Xr listen 2
+system call must be used after binding the socket with the
+.Xr bind 2
+system call.
+Only passive sockets may use the
+.Xr accept 2
+call to accept incoming connections.
+Only active sockets may use the
+.Xr connect 2
+call to initiate connections.
+.Pp
+RFCOMM sockets support
+.Dq "wildcard addressing" .
+In this case, socket must be bound to
+.Dv NG_HCI_BDADDR_ANY
+address.
+Note that RFCOMM channel field is always required.
+Once a connection has been established, the socket's address is fixed by the
+peer entity's location.
+The address assigned to the socket is the address associated with the
+Bluetooth device through which packets are being transmitted and received,
+and RFCOMM channel.
+.Pp
+The following options, which can be tested with
+.Xr getsockopt 2
+call, are defined at
+.Dv SOL_RFCOMM
+level for RFCOMM sockets:
+.Bl -tag -width foo
+.It Dv SO_RFCOMM_MTU
+Returns the maximum transfer unit size (in bytes) for the underlying RFCOMM
+channel.
+Note that application still can write/read bigger chunks to/from the socket.
+.It Dv SO_RFCOMM_FC_INFO
+Return the flow control information for the underlying RFCOMM channel.
+.El
+.Pp
+The
+.Va net.bluetooth.rfcomm.sockets.stream.timeout
+variable, that can be examined and set via
+.Xr sysctl 8 ,
+controls the connection timeout (in seconds) for RFCOMM sockets.
+.Sh HOOKS
+These node types support hooks with arbitrary names (as long as they are
+unique) and always accept hook connection requests.
+.Sh NETGRAPH CONTROL MESSAGES
+These node types support the generic control messages.
+.Sh SHUTDOWN
+These nodes are persistent and cannot be shut down.
+.Sh SEE ALSO
+.Xr btsockstat 1 ,
+.Xr socket 2 ,
+.Xr netgraph 4 ,
+.Xr ng_bluetooth 4 ,
+.Xr ng_hci 4 ,
+.Xr ng_l2cap 4 ,
+.Xr ngctl 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+module was implemented in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report if found.
diff --git a/share/man/man4/ng_h4.4 b/share/man/man4/ng_h4.4
new file mode 100644
index 0000000000..15764ed9ca
--- /dev/null
+++ b/share/man/man4/ng_h4.4
@@ -0,0 +1,123 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: ng_h4.4,v 1.2 2003/05/21 19:37:35 max Exp $
+.\" $FreeBSD: head/share/man/man4/ng_h4.4 267938 2014-06-26 21:46:14Z bapt $
+.\"
+.Dd June 14, 2002
+.Dt NG_H4 4
+.Os
+.Sh NAME
+.Nm ng_h4
+.Nd Netgraph node type that is also an H4 line discipline
+.Sh SYNOPSIS
+.In sys/types.h
+.In netgraph/bluetooth/include/ng_h4.h
+.Sh DESCRIPTION
+The
+.Nm h4
+node type is both a persistent Netgraph node type and a H4 line
+discipline.
+It implements a Bluetooth HCI UART transport layer as
+per chapter H4 of the Bluetooth Specification Book v1.1.
+A new node is created when the corresponding line discipline,
+.Dv H4DISC ,
+is registered on a tty device (see
+.Xr tty 4 ) .
+.Pp
+The node has a single hook called
+.Dv hook .
+Incoming bytes received on the tty device are re-assembled into
+HCI frames (according to the length).
+Full HCI frames are sent out on the hook.
+HCI frames received on
+.Dv hook
+are transmitted out on the tty device.
+No modification to the data is performed in either direction.
+While the line discipline is installed on a tty, the normal
+read and write operations are unavailable, returning
+.Er EIO .
+.Pp
+Information about the node is available via the netgraph
+.Xr ioctl 2
+command
+.Dv NGIOCGINFO .
+This command returns a
+.Vt "struct nodeinfo"
+similar to the
+.Dv NGM_NODEINFO
+.Xr netgraph 4
+control message.
+.Sh HOOKS
+This node type supports the following hooks:
+.Bl -tag -width ".Va hook"
+.It Va hook
+single HCI frame contained in single
+.Vt mbuf
+structure.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_H4_NODE_RESET
+Reset the node.
+.It Dv NGM_H4_NODE_GET_STATE
+Returns current receiving state for the node.
+.It Dv NGM_H4_NODE_GET_DEBUG
+Returns an integer containing the current debug level for the node.
+.It Dv NGM_H4_NODE_SET_DEBUG
+This command takes an integer argument and sets current debug level
+for the node.
+.It Dv NGM_H4_NODE_GET_QLEN
+Returns current length of outgoing queue for the node.
+.It Dv NGM_H4_NODE_SET_QLEN
+This command takes an integer argument and sets maximum length of
+outgoing queue for the node.
+.It Dv NGM_H4_NODE_GET_STAT
+Returns various statistic information for the node, such as: number of
+bytes (frames) sent, number of bytes (frames) received and number of
+input (output) errors.
+.It Dv NGM_H4_NODE_RESET_STAT
+Reset all statistic counters to zero.
+.El
+.Sh SHUTDOWN
+This node shuts down when the corresponding device is closed
+(or the line discipline is uninstalled on the device).
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr netgraph 4 ,
+.Xr tty 4 ,
+.Xr ngctl 8
+.Sh HISTORY
+The
+.Nm h4
+node type was implemented in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+This node still uses
+.Xr spltty 9
+to lock tty layer.
+This is wrong.
diff --git a/share/man/man4/ng_hci.4 b/share/man/man4/ng_hci.4
new file mode 100644
index 0000000000..9006acfb34
--- /dev/null
+++ b/share/man/man4/ng_hci.4
@@ -0,0 +1,387 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: ng_hci.4,v 1.3 2003/05/21 19:37:35 max Exp $
+.\" $FreeBSD: head/share/man/man4/ng_hci.4 267938 2014-06-26 21:46:14Z bapt $
+.\"
+.Dd June 25, 2002
+.Dt NG_HCI 4
+.Os
+.Sh NAME
+.Nm ng_hci
+.Nd Netgraph node type that is also a Bluetooth Host Controller Interface
+(HCI) layer
+.Sh SYNOPSIS
+.In sys/types.h
+.In netgraph/bluetooth/include/ng_hci.h
+.Sh DESCRIPTION
+The
+.Nm hci
+node type is a Netgraph node type that implements Bluetooth Host Controller
+Interface (HCI) layer as per chapter H1 of the Bluetooth Specification Book
+v1.1.
+.Sh INTRODUCTION TO BLUETOOTH
+Bluetooth is a short-range radio link intended to replace the cable(s)
+connecting portable and/or fixed electronic devices.
+Bluetooth operates in the unlicensed ISM band at 2.4 GHz.
+The Bluetooth protocol uses a
+combination of circuit and packet switching.
+Bluetooth can support an
+asynchronous data channel, up to three simultaneous synchronous voice
+channels, or a channel which simultaneously supports asynchronous data
+and synchronous voice.
+Each voice channel supports a 64 kb/s synchronous
+(voice) channel in each direction.
+The asynchronous channel can support
+maximal 723.2 kb/s asymmetric (and still up to 57.6 kb/s in the return
+direction), or 433.9 kb/s symmetric.
+.Pp
+The Bluetooth system provides a point-to-point connection (only two
+Bluetooth units involved), or a point-to-multipoint connection.
+In the point-to-multipoint connection,
+the channel is shared among several Bluetooth units.
+Two or more units sharing the same channel form a
+.Dq piconet .
+One Bluetooth unit acts as the master of the piconet, whereas the other
+unit(s) acts as slave(s).
+Up to seven slaves can be active in the piconet.
+In addition, many more slaves can remain locked to the master in a so-called
+parked state.
+These parked slaves cannot be active on the channel, but remain
+synchronized to the master.
+Both for active and parked slaves, the channel
+access is controlled by the master.
+.Pp
+Multiple piconets with overlapping coverage areas form a
+.Dq scatternet .
+Each piconet can only have a single master.
+However, slaves can participate
+in different piconets on a time-division multiplex basis.
+In addition, a master in one piconet can be a slave in another piconet.
+The piconets shall not be frequency-synchronized.
+Each piconet has its own hopping channel.
+.Ss Time Slots
+The channel is divided into time slots, each 625 usec in length.
+The time
+slots are numbered according to the Bluetooth clock of the piconet master.
+The slot numbering ranges from 0 to 2^27 -1 and is cyclic with a cycle length
+of 2^27.
+In the time slots, master and slave can transmit packets.
+.Ss SCO Link
+The SCO link is a symmetric, point-to-point link between the master and a
+specific slave.
+The SCO link reserves slots and can therefore be considered
+as a circuit-switched connection between the master and the slave.
+The SCO link typically supports time-bounded information like voice.
+The master can
+support up to three SCO links to the same slave or to different slaves.
+A slave can support up to three SCO links from the same master, or two SCO
+links if the links originate from different masters.
+SCO packets are never retransmitted.
+.Ss ACL Link
+In the slots not reserved for SCO links, the master can exchange packets
+with any slave on a per-slot basis.
+The ACL link provides a packet-switched
+connection between the master and all active slaves participating in the
+piconet.
+Both asynchronous and isochronous services are supported.
+Between a master and a slave only a single ACL link can exist.
+For most ACL packets,
+packet retransmission is applied to assure data integrity.
+.Sh HOST CONTROLLER INTERFACE (HCI)
+The HCI provides a command interface to the baseband controller and link
+manager, and access to hardware status and control registers.
+This interface
+provides a uniform method of accessing the Bluetooth baseband capabilities.
+.Pp
+The HCI layer on the Host exchanges data and commands with the HCI firmware
+on the Bluetooth hardware.
+The Host Controller Transport Layer (i.e., physical
+bus) driver provides both HCI layers with the ability to exchange information
+with each other.
+.Pp
+The Host will receive asynchronous notifications of HCI events independent
+of which Host Controller Transport Layer is used.
+HCI events are used for
+notifying the Host when something occurs.
+When the Host discovers that an
+event has occurred it will then parse the received event packet to determine
+which event occurred.
+The next sections specify the HCI packet formats.
+.Ss HCI Command Packet
+.Bd -literal -offset indent
+#define NG_HCI_CMD_PKT 0x01
+typedef struct {
+        uint8_t  type;   /* MUST be 0x1 */
+        uint16_t opcode; /* OpCode */
+        uint8_t  length; /* parameter(s) length in bytes */
+} __attribute__ ((packed)) ng_hci_cmd_pkt_t;
+.Ed
+.Pp
+The HCI command packet is used to send commands to the Host Controller
+from the Host.
+When the Host Controller completes most of the commands,
+a Command Complete event is sent to the Host.
+Some commands do not receive
+a Command Complete event when they have been completed.
+Instead, when the
+Host Controller receives one of these commands the Host Controller sends
+a Command Status event back to the Host when it has begun to execute the
+command.
+Later on, when the actions associated with the command have finished,
+an event that is associated with the sent command will be sent by the Host
+Controller to the Host.
+.Ss HCI Event Packet
+.Bd -literal -offset indent
+#define NG_HCI_EVENT_PKT 0x04
+typedef struct {
+        uint8_t type;   /* MUST be 0x4 */
+        uint8_t event;  /* event */
+        uint8_t length; /* parameter(s) length in bytes */
+} __attribute__ ((packed)) ng_hci_event_pkt_t;
+.Ed
+.Pp
+The HCI event packet is used by the Host Controller to notify the Host
+when events occur.
+.Ss HCI ACL Data Packet
+.Bd -literal -offset indent
+#define NG_HCI_ACL_DATA_PKT 0x02
+typedef struct {
+        uint8_t  type;       /* MUST be 0x2 */
+        uint16_t con_handle; /* connection handle + PB + BC flags */
+        uint16_t length;     /* payload length in bytes */
+} __attribute__ ((packed)) ng_hci_acldata_pkt_t;
+.Ed
+.Pp
+HCI ACL data packets are used to exchange ACL data between the Host and
+Host Controller.
+.Ss HCI SCO Data Packet
+.Bd -literal -offset indent
+#define NG_HCI_SCO_DATA_PKT 0x03
+typedef struct {
+        uint8_t  type;       /* MUST be 0x3 */
+        uint16_t con_handle; /* connection handle + reserved bits */
+        uint8_t  length;     /* payload length in bytes */
+} __attribute__ ((packed)) ng_hci_scodata_pkt_t;
+.Ed
+.Pp
+HCI SCO data packets are used to exchange SCO data between the Host and
+Host Controller.
+.Sh HCI INITIALIZATION
+On initialization, HCI control application must issue the following HCI
+commands (in any order).
+.Bl -tag -width foo
+.It Dv Read_BD_ADDR
+To obtain BD_ADDR of the Bluetooth unit.
+.It Dv Read_Local_Supported_Features
+To obtain the list of features supported by Bluetooth unit.
+.It Dv Read_Buffer_Size
+To determine the maximum size of HCI ACL and SCO HCI data packets (excluding
+header) that can be sent from the Host to the Host Controller.
+There are also
+two additional return parameters that specify the total number of HCI ACL and
+SCO data packets that the Host Controller can have waiting for transmission in
+its buffers.
+.El
+.Pp
+As soon as HCI initialization has been successfully performed, HCI control
+application must turn on
+.Dq inited
+bit for the node.
+Once HCI node has been initialized all upstream hooks
+will receive a
+.Dv NGM_HCI_NODE_UP
+Netgraph message defined as follows.
+.Bd -literal -offset indent
+#define NGM_HCI_NODE_UP 112 /* HCI -> Upper */
+typedef struct {
+        uint16_t  pkt_size; /* max. ACL/SCO packet size (w/o hdr) */
+        uint16_t  num_pkts; /* ACL/SCO packet queue size */
+        uint16_t  reserved; /* place holder */
+        bdaddr_t  bdaddr;   /* bdaddr */
+} ng_hci_node_up_ep;
+.Ed
+.Sh HCI FLOW CONTROL
+HCI layer performs flow control on baseband connection basis (i.e., ACL and
+SCO link).
+Each baseband connection has
+.Dq "connection handle"
+and queue of outgoing data packets.
+Upper layers protocols are allowed to
+send up to
+.Dv ( num_pkts
+\-
+.Dv pending )
+packets at one time.
+HCI layer will send
+.Dv NGM_HCI_SYNC_CON_QUEUE
+Netgraph messages to inform upper layers about current queue state for each
+connection handle.
+The
+.Dv NGM_HCI_SYNC_CON_QUEUE
+Netgraph message is defined as follows.
+.Bd -literal -offset indent
+#define NGM_HCI_SYNC_CON_QUEUE 113 /* HCI -> Upper */
+typedef struct {
+        uint16_t con_handle; /* connection handle */
+        uint16_t completed;  /* number of completed packets */
+} ng_hci_sync_con_queue_ep;
+.Ed
+.Sh HOOKS
+This node type supports the following hooks:
+.Bl -tag -width ".Va drv"
+.It Va drv
+Bluetooth Host Controller Transport Layer hook.
+Single HCI packet contained in single
+.Vt mbuf
+structure.
+.It Va acl
+Upper layer protocol/node is connected to the hook.
+Single HCI ACL data packet contained in single
+.Vt mbuf
+structure.
+.It Va sco
+Upper layer protocol/node is connected to the hook.
+Single HCI SCO data packet contained in single
+.Vt mbuf
+structure.
+.It Va raw
+Raw hook.
+Every HCI frame (including HCI command frame) that goes in
+or out will be delivered to the hook.
+Usually the Bluetooth raw HCI socket layer is connected to the hook.
+Single HCI frame contained in single
+.Vt mbuf
+structure.
+.El
+.Sh BLUETOOTH UPPER LAYER PROTOCOLS INTERFACE (LP CONTROL MESSAGES)
+.Bl -tag -width foo
+.It Dv NGM_HCI_LP_CON_REQ
+Requests the lower protocol to create a connection.
+If a physical link
+to the remote device does not exist, this message must be sent to the lower
+protocol (baseband) to establish the physical connection.
+.It Dv NGM_HCI_LP_DISCON_REQ
+Requests the lower protocol (baseband) to terminate a connection.
+.It Dv NGM_HCI_LP_CON_CFM
+Confirms success or failure of the
+.Dv NGM_HCI_LP_CON_REQ
+request to establish a lower layer (baseband) connection.
+This includes passing the authentication challenge if authentication is
+required to establish the physical link.
+.It Dv NGM_HCI_LP_CON_IND
+Indicates the lower protocol (baseband) has successfully established
+incoming connection.
+.It Dv NGM_HCI_LP_CON_RSP
+A response accepting or rejecting the previous connection indication request.
+.It Dv NGM_HCI_LP_DISCON_IND
+Indicates the lower protocol (baseband) has terminated connection.
+This could be a response to
+.Dv NGM_HCI_LP_DISCON_REQ
+or a timeout event.
+.It Dv NGM_HCI_LP_QOS_REQ
+Requests the lower protocol (baseband) to accommodate a particular QoS
+parameter set.
+.It Dv NGM_HCI_LP_QOS_CFM
+Confirms success or failure of the request for a given quality of service.
+.It Dv NGM_HCI_LP_QOS_IND
+Indicates the lower protocol (baseband) has detected a violation of the QoS
+agreement.
+.El
+.Sh NETGRAPH CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_HCI_NODE_GET_STATE
+Returns current state for the node.
+.It Dv NGM_HCI_NODE_INIT
+Turn on
+.Dq inited
+bit for the node.
+.It Dv NGM_HCI_NODE_GET_DEBUG
+Returns an integer containing the current debug level for the node.
+.It Dv NGM_HCI_NODE_SET_DEBUG
+This command takes an integer argument and sets current debug level
+for the node.
+.It Dv NGM_HCI_NODE_GET_BUFFER
+Returns current state of data buffers.
+.It Dv NGM_HCI_NODE_GET_BDADDR
+Returns BD_ADDR as cached in the node.
+.It Dv NGM_HCI_NODE_GET_FEATURES
+Returns the list of features supported by hardware (as cached by the node).
+.It Dv NGM_HCI_NODE_GET_NEIGHBOR_CACHE
+Returns content of the neighbor cache.
+.It Dv NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE
+Remove all neighbor cache entries.
+.It Dv NGM_HCI_NODE_GET_CON_LIST
+Returns list of active baseband connections (i.e., ACL and SCO links).
+.It Dv NGM_HCI_NODE_GET_STAT
+Returns various statistic counters.
+.It Dv NGM_HCI_NODE_RESET_STAT
+Resets all statistic counters to zero.
+.It NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK
+Sets current link policy settings mask.
+After the new ACL connection is
+created the HCI node will try set link policy for the ACL connection.
+By default, every supported Link Manager (LM) mode will be enabled.
+User can
+override this by setting link policy settings mask which specifies LM
+modes to be enabled.
+.It NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK
+Returns current link policy settings mask.
+.It NGM_HCI_NODE_SET_PACKET_MASK
+Sets current packet mask.
+When new baseband (ACL or SCO) connection is
+created the HCI node will specify every packet type supported by the device.
+User can override this by setting packet mask which specifies packet types
+to be used for new baseband connections.
+.It NGM_HCI_NODE_GET_PACKET_MASK
+Returns current packet mask.
+.It NGM_HCI_NODE_SET_ROLE_SWITCH
+Sets the value of the role switch.
+Role switch is enabled when this value is not zero.
+This is the default state.
+Note that actual role switch at Bluetooth link level will only be performed if
+hardware supports role switch and it was enabled.
+.It NGM_HCI_NODE_GET_ROLE_SWITCH
+Returns the value of the role switch for the node.
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or
+when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr hccontrol 8 ,
+.Xr ngctl 8
+.Sh HISTORY
+The
+.Nm hci
+node type was implemented in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report if found.
diff --git a/share/man/man4/ng_l2cap.4 b/share/man/man4/ng_l2cap.4
new file mode 100644
index 0000000000..8a3bf8e671
--- /dev/null
+++ b/share/man/man4/ng_l2cap.4
@@ -0,0 +1,422 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: ng_l2cap.4,v 1.4 2003/09/14 23:37:52 max Exp $
+.\" $FreeBSD: head/share/man/man4/ng_l2cap.4 267938 2014-06-26 21:46:14Z bapt $
+.\"
+.Dd July 4, 2002
+.Dt NG_L2CAP 4
+.Os
+.Sh NAME
+.Nm ng_l2cap
+.Nd Netgraph node type that implements Bluetooth Logical Link Control and
+Adaptation Protocol (L2CAP)
+.Sh SYNOPSIS
+.In sys/types.h
+.In netgraph/bluetooth/include/ng_hci.h
+.In netgraph/bluetooth/include/ng_l2cap.h
+.Sh DESCRIPTION
+The
+.Nm l2cap
+node type is a Netgraph node type that implements Bluetooth Logical Link
+Control and Adaptation Protocol as per chapter D of the Bluetooth Specification
+Book v1.1.
+.Pp
+L2CAP provides connection-oriented and connectionless data services to upper
+layer protocols with protocol multiplexing capability, segmentation and
+reassembly operation, and group abstractions.
+L2CAP permits higher level
+protocols and applications to transmit and receive L2CAP data packets up to
+64 kilobytes in length.
+.Ss L2CAP Assumptions
+.Bl -enum -offset indent
+.It
+The ACL link between two units is set up.
+The Baseband provides orderly
+delivery of data packets, although there might be individual packet corruption
+and duplicates.
+No more than one ACL link exists between any two devices.
+.It
+The Baseband always provides the impression of full-duplex communication
+channels.
+This does not imply that all L2CAP communications are bi-directional.
+Multicasts and unidirectional traffic (e.g., video) do not require duplex
+channels.
+.It
+L2CAP provides a reliable channel using the mechanisms available at the
+Baseband layer.
+The Baseband always performs data integrity checks when
+requested and resends data until it has been successfully acknowledged or
+a timeout occurs.
+As acknowledgements may be lost, timeouts may
+occur even after the data has been successfully sent.
+.El
+.Sh L2CAP GENERAL OPERATION
+The Logical Link Control and Adaptation Protocol (L2CAP) is based around the
+concept of
+.Dq channels .
+Each channel is bound to a single protocol in a many-to-one fashion.
+Multiple
+channels can be bound to the same protocol, but a channel cannot be bound to
+multiple protocols.
+Each L2CAP packet received on a channel is directed to
+the appropriate higher level protocol.
+.Pp
+Each one of the end-points of an L2CAP channel is referred to by a channel
+identifier.
+Channel identifiers (CIDs) are local names representing a logical
+channel end-point on the device.
+Identifiers from 0x0001 to 0x003F are reserved
+for specific L2CAP functions.
+The null identifier (0x0000) is defined as an
+illegal identifier and must never be used as a destination end-point.
+All L2CAP signalling commands are sent to CID 0x0001.
+CID 0x0002 is reserved for group-oriented channel.
+The same CID must not be reused as a local L2CAP
+channel endpoint for multiple simultaneous L2CAP channels between a local
+device and some remote device.
+.Pp
+CID assignment is relative to a particular device and a device can assign CIDs
+independently from other devices.
+Thus, even if the same CID value has been
+assigned to (remote) channel endpoints by several remote devices connected
+to a single local device, the local device can still uniquely associate each
+remote CID with a different device.
+.Ss Channel Operational States
+.Bl -tag -width foo
+.It Dv NG_L2CAP_CLOSED
+In this state, there is no channel associated with this CID.
+This is the only
+state when a link level connection (Baseband) may not exist.
+Link disconnection
+forces all other states into the
+.Dv NG_L2CAP_CLOSED
+state.
+.It Dv NG_L2CAP_W4_L2CAP_CON_RSP
+In this state, the CID represents a local end-point and an L2CAP Connect
+Request message has been sent referencing this endpoint and it is now waiting
+for the corresponding L2CAP Connect Response message.
+.It Dv NG_L2CAP_W4_L2CA_CON_RSP
+In this state, the remote end-point exists and an L2CAP Connect Request has
+been received by the local L2CAP entity.
+An L2CA Connect Indication has been
+sent to the upper layer and the part of the local L2CAP entity processing the
+received L2CAP Connect Request waits for the corresponding response.
+The response may require a security check to be performed.
+.It Dv NG_L2CAP_CONFIG
+In this state, the connection has been established but both sides are still
+negotiating the channel parameters.
+The Configuration state may also be
+entered when the channel parameters are being renegotiated.
+Prior to entering the
+.Dv NG_L2CAP_CONFIG
+state, all outgoing data traffic is suspended since
+the traffic parameters of the data traffic are to be renegotiated.
+Incoming
+data traffic is accepted until the remote channel endpoint has entered
+the
+.Dv NG_L2CAP_CONFIG
+state.
+In the
+.Dv NG_L2CAP_CONFIG
+state, both sides will issue
+L2CAP Configuration Request messages if only defaults are being used, a null
+message will be sent.
+If a large amount of parameters need to be negotiated,
+multiple messages will be sent to avoid any MTU limitations and negotiate
+incrementally.
+Moving from the
+.Dv NG_L2CAP_CONFIG
+state to the
+.Dv NG_L2CAP_OPEN
+state requires both sides to be ready.
+An L2CAP entity is ready when it has received
+a positive response to its final request and it has positively responded to
+the final request from the remote device.
+.It Dv NG_L2CAP_OPEN
+In this state, the connection has been established and configured, and data
+flow may proceed.
+.It Dv NG_L2CAP_W4_L2CAP_DISCON_RSP
+In this state, the connection is shutting down and an L2CAP Disconnect Request
+message has been sent.
+This state is now waiting for the corresponding response.
+.It Dv NG_L2CAP_W4_L2CA_DISCON_RSP
+In this state, the connection on the remote endpoint is shutting down and an
+L2CAP Disconnect Request message has been received.
+An L2CA Disconnect
+Indication has been sent to the upper layer to notify the owner of the CID
+that the remote endpoint is being closed.
+This state is now waiting for the
+corresponding response from the upper layer before responding to the remote
+endpoint.
+.El
+.Ss Protocol Multiplexing
+L2CAP supports protocol multiplexing because the Baseband Protocol does not
+support any
+.Dq type
+field identifying the higher layer protocol being multiplexed above it.
+L2CAP is able to distinguish between upper layer protocols such as the Service
+Discovery Protocol, RFCOMM and Telephony Control.
+.Ss Segmentation and Reassembly
+The data packets defined by the Baseband Protocol are limited in size.
+Large
+L2CAP packets must be segmented into multiple smaller Baseband packets prior
+to their transmission over the air.
+Similarly, multiple received Baseband
+packets may be reassembled into a single larger L2CAP packet.
+.Ss Quality of Service
+The L2CAP connection establishment process allows the exchange of information
+regarding the quality of service (QoS) expected between two Bluetooth units.
+.Ss Groups
+The Baseband Protocol supports the concept of a piconet, a group of devices
+synchronously hopping together using the same clock.
+The L2CAP group
+abstraction permits implementations to efficiently map protocol groups on to
+piconets.
+.Pp
+The following features are outside the scope of L2CAP responsibilities:
+.Bl -dash -offset indent
+.It
+L2CAP does not transport audio designated for SCO links.
+.It
+L2CAP does not enforce a reliable channel or ensure data integrity,
+that is, L2CAP performs no retransmissions or checksum calculations.
+.It
+L2CAP does not support a reliable multicast channel.
+.It
+L2CAP does not support the concept of a global group name.
+.El
+.Sh HOOKS
+This node type supports the following hooks:
+.Bl -tag -width ".Va hci"
+.It Va hci
+Bluetooth Host Controller Interface downstream hook.
+.It Va l2c
+Upper layer protocol upstream hook.
+Usually the Bluetooth L2CAP socket layer is connected to the hook.
+.It Va ctl
+Control hook.
+Usually the Bluetooth raw L2CAP sockets layer is connected to the hook.
+.El
+.Sh INTERFACE TO THE UPPER LAYER PROTOCOLS (L2CA CONTROL MESSAGES)
+Bluetooth specification says that L2CA request must block until response
+is ready.
+L2CAP node uses
+.Va token
+field from Netgraph message header to match L2CA request and response.
+The upper layer protocol must populate
+.Va token .
+L2CAP node will queue request and start processing.
+Later, when response is
+ready or timeout has occurred, L2CAP node will create new Netgraph message, set
+.Va token
+and
+.Dv NFG_RESP
+flag and send message to the upper layer.
+Note that L2CA indication messages
+will not populate
+.Va token
+and will not set
+.Dv NGF_RESP
+flag.
+There is no reason for this, because they are just notifications and do
+not require acknowledgment.
+.Bl -tag -width foo
+.It Dv NGM_L2CAP_L2CA_CON
+Requests the creation of a channel representing a logical connection to a
+physical address.
+Input parameters are the target protocol (PSM) and remote
+device's 48-bit address (BD_ADDR).
+Output parameters are the local CID (LCID)
+allocated by the local L2CAP entity, and Result of the request.
+If Result
+indicates a pending notification, the Status value may contain more information
+of what processing is delaying the establishment of the connection.
+.It Dv NGM_L2CAP_L2CA_CON_IND
+This message includes the parameters for the address of the remote device that
+issued the connection request, the local CID representing the channel being
+requested, the Identifier contained in the request, and the PSM value the
+request is targeting.
+.It Dv NGM_L2CAP_L2CA_CON_RSP
+Issues a response to a connection request event indication.
+Input parameters
+are the remote device's 48-bit address, Identifier sent in the request, local
+CID, the Response code, and the Status attached to the Response code.
+The output parameter is the Result of the service request.
+This primitive must be
+called no more than once after receiving the indication.
+.It Dv NGM_L2CAP_L2CA_CFG
+Requests the initial configuration (or reconfiguration) of a channel to a new
+set of channel parameters.
+Input parameters are the local CID endpoint, new
+incoming receivable MTU (InMTU), new outgoing flow spec-ification, and flush
+and link timeouts.
+Output parameters are the Result, accepted incoming MTU
+(InMTU), the remote side's flow requests, and flush and link timeouts.
+.It Dv NGM_L2CAP_L2CA_CFG_IND
+This message includes the parameters indicating the local CID of the channel
+the request has been sent to, the outgoing MTU size (maximum packet that can
+be sent across the channel) and the flowspec describing the characteristics of
+the incoming data.
+All other channel parameters are set to their default values
+if not provided by the remote device.
+.It Dv NGM_L2CAP_L2CA_CFG_RSP
+Issues a response to a configuration request event indication.
+Input parameters
+include the local CID of the endpoint being configured, outgoing transmit MTU
+(which may be equal or less to the OutMTU parameter in the configuration
+indication event) and the accepted flowspec for incoming traffic.
+The output parameter is the Result value.
+.It Dv NGM_L2CAP_L2CA_QOS_IND
+This message includes the parameter indicating the address of the remote
+Bluetooth device where the QoS contract has been violated.
+.It Dv NGM_L2CAP_L2CA_DISCON
+Requests the disconnection of the channel.
+Input parameter is the CID representing the local channel endpoint.
+Output parameter is Result.
+Result
+is zero if an L2CAP Disconnect Response is received, otherwise a non-zero value
+is returned.
+Once disconnection has been requested, no process will be able to
+successfully read or write from the CID.
+.It Dv NGM_L2CAP_L2CA_DISCON_IND
+This message includes the parameter indicating the local CID the request has
+been sent to.
+.It Dv NGM_L2CAP_L2CA_WRITE
+Response to transfer of data request.
+Actual data must be received from
+appropriate upstream hook and must be prepended with header defined as follows.
+.Bd -literal -offset indent
+/* L2CA data packet header */
+typedef struct {
+        uint32_t token;  /* token to use in L2CAP_L2CA_WRITE */
+        uint16_t length; /* length of the data */
+        uint16_t lcid;   /* local channel ID */
+} __attribute__ ((packed)) ng_l2cap_l2ca_hdr_t;
+.Ed
+.Pp
+The output parameters are Result and Length of data written.
+.It Dv NGM_L2CAP_L2CA_GRP_CREATE
+Requests the creation of a CID to represent a logical connection to multiple
+devices.
+Input parameter is the PSM value that the outgoing connectionless
+traffic is labelled with, and the filter used for incoming traffic.
+Output parameter is the CID representing the local endpoint.
+On creation, the group
+is empty but incoming traffic destined for the PSM value is readable.
+.Bf -emphasis
+This request has not been implemented.
+.Ef
+.It Dv NGM_L2CAP_L2CA_GRP_CLOSE
+The use of this message closes down a Group.
+.Bf -emphasis
+This request has not been implemented.
+.Ef
+.It Dv NGM_L2CAP_L2CA_GRP_ADD_MEMBER
+Requests the addition of a member to a group.
+The input parameter includes the
+CID representing the group and the BD_ADDR of the group member to be added.
+The output parameter Result confirms the success or failure of the request.
+.Bf -emphasis
+This request has not been implemented.
+.Ef
+.It Dv NGM_L2CAP_L2CA_GRP_REM_MEMBER
+Requests the removal of a member from a group.
+The input parameters include
+the CID representing the group and BD_ADDR of the group member to be removed.
+The output parameter Result confirms the success or failure of the request.
+.Bf -emphasis
+This request has not been implemented.
+.Ef
+.It Dv NGM_L2CAP_L2CA_GRP_MEMBERSHIP
+Requests a report of the members of a group.
+The input parameter CID represents the group being queried.
+The output parameter Result confirms the success or
+failure of the operation.
+If the Result is successful, BD_ADDR_Lst is a list
+of the Bluetooth addresses of the N members of the group.
+.Bf -emphasis
+This request has not been implemented.
+.Ef
+.It Dv NGM_L2CAP_L2CA_PING
+Initiates an L2CA Echo Request message and the reception of the corresponding
+L2CAP Echo Response message.
+The input parameters are remote Bluetooth device
+BD_ADDR, Echo Data and Length of the echo data.
+The output parameters are
+Result, Echo Data and Length of the echo data.
+.It Dv NGM_L2CAP_L2CA_GET_INFO
+Initiates an L2CA Information Request message and the reception of the
+corresponding L2CAP Info Response message.
+The input parameters are remote Bluetooth device BD_ADDR and Information Type.
+The output parameters are
+Result, Information Data and Size of the information data.
+.It Dv NGM_L2CAP_L2CA_ENABLE_CLT
+Request to disable (enable) the reception of connectionless packets.
+The input
+parameter is the PSM value indicating service that should be blocked
+(unblocked) and Enable flag.
+.El
+.Sh NETGRAPH CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width foo
+.It Dv NGM_L2CAP_NODE_GET_FLAGS
+Returns current state for the node.
+.It Dv NGM_L2CAP_NODE_GET_DEBUG
+Returns an integer containing the current debug level for the node.
+.It Dv NGM_L2CAP_NODE_SET_DEBUG
+This command takes an integer argument and sets current debug level
+for the node.
+.It Dv NGM_L2CAP_NODE_GET_CON_LIST
+Returns list of active baseband connections (i.e., ACL links).
+.It Dv NGM_L2CAP_NODE_GET_CHAN_LIST
+Returns list of active L2CAP channels.
+.It Dv NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO
+Returns an integer containing the current value of the auto disconnect
+timeout (in sec).
+.It Dv NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO
+This command accepts an integer and sets the value of the auto disconnect
+timeout (in sec).
+The special value of 0 (zero) disables auto disconnect timeout.
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of an
+.Dv NGM_SHUTDOWN
+control message, or
+when all hooks have been disconnected.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr l2control 8 ,
+.Xr l2ping 8 ,
+.Xr ngctl 8
+.Sh HISTORY
+The
+.Nm l2cap
+node type was implemented in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report if found.
diff --git a/share/man/man4/ng_ubt.4 b/share/man/man4/ng_ubt.4
new file mode 100644
index 0000000000..6a767fb170
--- /dev/null
+++ b/share/man/man4/ng_ubt.4
@@ -0,0 +1,125 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: ng_ubt.4,v 1.3 2003/05/21 19:37:35 max Exp $
+.\" $FreeBSD: head/share/man/man4/ng_ubt.4 267938 2014-06-26 21:46:14Z bapt $
+.\"
+.Dd December 26, 2012
+.Dt NG_UBT 4
+.Os
+.Sh NAME
+.Nm ng_ubt
+.Nd Netgraph node type that is also a driver for Bluetooth USB devices
+.Sh SYNOPSIS
+.In sys/types.h
+.In netgraph/bluetooth/include/ng_ubt.h
+.Sh DESCRIPTION
+The
+.Nm ubt
+node type is both a persistent Netgraph node type and a driver for
+Bluetooth USB devices.
+It implements a Bluetooth USB transport layer
+as per chapter H2 of the Bluetooth Specification Book v1.1.
+A new node is created when a supported USB device is plugged in.
+.Pp
+The node has a single hook called
+.Dv hook .
+Incoming bytes received on the device are re-assembled into HCI frames
+(according to the length).
+Full HCI frames are sent out on the hook.
+The node will add a HCI frame indicator if the device did not send it.
+HCI frames received on
+.Dv hook
+are transmitted out.
+The node will drop the HCI frame indicator unless the device
+requires it to be present.
+.Sh HARDWARE
+The
+.Nm
+driver supports all Bluetooth USB devices that conform with
+the Bluetooth specification v1.1, including:
+.Pp
+.Bl -bullet -compact
+.It
+3Com 3CREB96
+.It
+AIPTEK BR0R02
+.It
+EPoX BT-DG02
+.It
+Mitsumi Bluetooth USB adapter
+.It
+MSI MS-6967
+.It
+TDK Bluetooth USB adapter
+.It
+Broadcom Bluetooth USB adapter
+.El
+.Sh HOOKS
+This node type supports the following hooks:
+.Bl -tag -width ".Va hook"
+.It Va hook
+single HCI frame contained in a single
+.Vt mbuf
+structure.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width indent
+.It Dv NGM_UBT_NODE_GET_DEBUG Pq Ic get_debug
+Returns an integer containing the current debug level for the node.
+.It Dv NGM_UBT_NODE_SET_DEBUG Pq Ic set_debug
+This command takes an integer argument and sets the current debug level
+for the node.
+.It Dv NGM_UBT_NODE_GET_QLEN Pq Ic get_qlen
+This command takes a parameter that specifies the queue number and returns
+the current maximal length of the queue for the node.
+.It Dv NGM_UBT_NODE_SET_QLEN Pq Ic set_qlen
+This command takes two parameters that specify the queue number and the maximum
+length of the queue and sets the maximal length of the queue for the node.
+.It Dv NGM_UBT_NODE_GET_STAT Pq Ic get_stat
+Returns various statistic information for the node, such as: number of
+bytes (frames) sent, number of bytes (frames) received and number of
+input (output) errors.
+.It Dv NGM_UBT_NODE_RESET_STAT Pq Ic reset_stat
+Reset all statistic counters to zero.
+.El
+.Sh SHUTDOWN
+This node shuts down when the corresponding USB device is un-plugged.
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ugen 4 ,
+.Xr usb 4 ,
+.Xr ngctl 8
+.Sh HISTORY
+The
+.Nm ubt
+node type was implemented in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Isochronous USB transfers are broken.
+This means that the USB device will not be able to transfer SCO data (voice).
+USB interrupt transfers are implemented as bulk-in transfers (not really a bug).
diff --git a/share/man/man4/ubt.4 b/share/man/man4/ubt.4
deleted file mode 100644
index ded852e573..0000000000
--- a/share/man/man4/ubt.4
+++ /dev/null
@@ -1,149 +0,0 @@
-.\" $NetBSD: ubt.4,v 1.5 2006/09/02 23:54:23 wiz Exp $
-.\"
-.\" Copyright (c) 2006 Itronix Inc.
-.\" All rights reserved.
-.\"
-.\" Written by Iain Hibbert for Itronix Inc.
-.\"
-.\" 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. The name of Itronix Inc. may not be used to endorse
-.\"    or promote products derived from this software without specific
-.\"    prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
-.\"
-.Dd August 27, 2006
-.Dt UBT 4
-.Os
-.Sh NAME
-.Nm ubt
-.Nd USB Bluetooth driver
-.Sh SYNOPSIS
-To compile this driver into the kernel,
-place the following lines in your
-kernel configuration file:
-.Bd -ragged -offset indent
-.Cd "device ubt"
-.Ed
-.Pp
-Alternatively, to load the driver as a
-module at boot time, place the following line in
-.Xr loader.conf 5 :
-.Bd -literal -offset indent
-ubt_load="YES"
-.Ed
-.Sh DESCRIPTION
-The
-.Nm
-driver provides support for USB Bluetooth dongles
-to the Bluetooth protocol stack.
-.Pp
-USB Bluetooth dongles provide two interfaces, both of which the
-.Nm
-driver claims.
-The second interface is used for Isochronous data and will have
-several alternate configurations regarding bandwidth consumption,
-which can be set using the hw.ubtN.config
-.Xr sysctl 8
-variable.
-The number of alternate configurations is indicated by the value
-in the hw.ubtN.alt_config variable, and the isoc frame size for the current
-configuration is shown in the hw.ubtN.sco_rxsize and hw.ubtN.sco_txsize
-variables.
-.Pp
-By default, configuration 0 is selected, which means that no bandwidth
-is used on the Isochronous interface and no SCO data can be sent.
-Consult the Bluetooth USB specification at https://www.bluetooth.org/
-for complete instructions on setting bandwidth consumption.
-The following extract may be
-useful as a general guidance though details may differ between manufacturers.
-.Pp
-.Bl -tag -compact -width XXX
-.It 0
-No active voice channels
-.It 1
-One voice channel with 8-bit encoding
-.It 2
-Two voice channels with 8-bit encoding, or one voice channel with
-16-bit encoding.
-.It 3
-Three voice channels with 8-bit encoding
-.It 4
-Two voice channels with 16-bit encoding
-.It 5
-Three voice channels with 16-bit encoding
-.El
-.Sh SEE ALSO
-.Xr bluetooth 4 ,
-.\".Xr uhub 4 ,
-.Xr sysctl 8
-.Sh HISTORY
-This
-.Nm
-device driver was originally a character device written by
-.An David Sainty
-and
-.An Lennart Augustsson .
-It was rewritten to support socket based Bluetooth access for
-.Nx 4.0
-by
-.An Iain Hibbert .
-The
-.Nm
-driver was imported into
-.Dx 1.11 .
-.Sh CAVEATS
-Isochronous data is seemingly not well supported over USB in the current
-system and to get SCO working, you may have to calculate the SCO packet
-size that the stack will use.
-This is the sco_mtu value reported by the
-.Xr btconfig 8
-command, and when combined with the SCO header (3 bytes) should
-fit exactly into an integer number of Isochronous data frames where
-the frame size is indicated by the
-.Sq hw.ubtN.sco_txsize
-sysctl variable.
-.Pp
-For example: I want one voice channel (which is all that is supported,
-for now) so am using configuration #2, with a frame length of 17
-bytes.
-This gives possible values of:
-.Pp
-.Dl "(17 * 1) - 3 = 14"
-.Dl "(17 * 2) - 3 = 31"
-.Dl "(17 * 3) - 3 = 48"
-.Dl "(17 * 4) - 3 = 65"
-.Dl "(17 * 5) - 3 = 82"
-.Dl "etc."
-.Pp
-.Xr btconfig 8
-shows the maximum SCO payload as 64 bytes, so I am using the next smaller
-size of 48, to minimize the overhead of the 3 header bytes.
-.Pp
-The SCO packet size can be changed using the
-.Sq scomtu
-option to
-.Xr btconfig 8 .
-.Pp
-The failure mode is that the USB Bluetooth dongle locks up though
-generally removal/reinsertion will clear the problem.
-.Sh BUGS
-The Isochronous configuration can only be changed when the device is not
-marked up.
diff --git a/share/man/man4/ubtbcmfw.4 b/share/man/man4/ubtbcmfw.4
new file mode 100644
index 0000000000..084baa04eb
--- /dev/null
+++ b/share/man/man4/ubtbcmfw.4
@@ -0,0 +1,108 @@
+.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: ubtbcmfw.4,v 1.3 2003/05/21 19:37:35 max Exp $
+.\" $FreeBSD: head/share/man/man4/ubtbcmfw.4 267938 2014-06-26 21:46:14Z bapt $
+.\"
+.Dd November 22, 2006
+.Dt UBTBCMFW 4
+.Os
+.Sh NAME
+.Nm ubtbcmfw
+.Nd Firmware driver for Broadcom BCM2033 chip based Bluetooth USB devices
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following line in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device ubtbcmfw"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+ubtbcmfw_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+is a firmware driver for Broadcom BCM2033 chip based Bluetooth USB devices.
+It provides minimal access to the parts of the device required to download
+firmware.
+.Pp
+The
+.Nm
+driver creates three fixed endpoint device nodes.
+.Pp
+The control transfers can only happen on the control endpoint which
+is always endpoint 0.
+Control requests are issued by
+.Xr ioctl 2
+calls.
+.Pp
+Only incoming transfers are supported on an interrupt endpoint.
+To perform I/O on an interrupt endpoint,
+.Xr read 2
+should be used.
+All I/O operations on an interrupt endpoint are unbuffered.
+Interrupt endpoint is always endpoint 1.
+.Pp
+Only outgoing bulk transfers are supported on a bulk endpoint.
+To perform I/O on a bulk endpoint,
+.Xr write 2
+should be used.
+All I/O operations on a bulk endpoint are unbuffered.
+Outgoing bulk endpoint is always endpoint 2.
+.Pp
+The control endpoint (endpoint 0) handles the following
+.Xr ioctl 2
+calls:
+.Bl -tag -width indent
+.It Dv USB_GET_DEVICE_DESC Pq Vt usb_device_descriptor_t
+Return the device descriptor.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /dev/ubtbcmfw Ns Ar N Ns Pa \&. Ns Ar EE" -compact
+.It Pa /dev/ubtbcmfw Ns Ar N Ns Pa \&. Ns Ar EE
+Endpoint
+.Ar EE
+of device
+.Ar N .
+.El
+.Sh SEE ALSO
+.Xr ng_ubt 4 ,
+.Xr ugen 4 ,
+.Xr usb 4 ,
+.Xr bcmfw 8
+.Sh HISTORY
+The
+.Nm
+driver was implemented in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report if found.
diff --git a/share/man/man4/usb.4 b/share/man/man4/usb.4
index 3867ada253..16b0c90998 100644
--- a/share/man/man4/usb.4
+++ b/share/man/man4/usb.4
@@ -123,8 +123,8 @@ NDIS miniport driver wrapper
 Ralink Technology RT2501USB/RT2601USB IEEE 802.11 driver
 .It Xr run 4
 Ralink Technology RT2700U/RT2800U/RT3000U IEEE 802.11 driver
-.\".It Xr ubt 4
-.\"Bluetooth adapters
+.It Xr ng_ubt 4
+Bluetooth adapters
 .It Xr urndis 4
 RNDIS USB ethernet driver
 .It Xr urtwn 4
@@ -268,6 +268,7 @@ specifications can be found at:
 .Xr kue 4 ,
 .Xr mos 4 ,
 .Xr ndis 4 ,
+.Xr ng_ubt 4 ,
 .Xr ohci 4 ,
 .Xr pci 4 ,
 .Xr rum 4 ,
diff --git a/share/man/man5/bluetooth.device.conf.5 b/share/man/man5/bluetooth.device.conf.5
new file mode 100644
index 0000000000..4068787ce0
--- /dev/null
+++ b/share/man/man5/bluetooth.device.conf.5
@@ -0,0 +1,186 @@
+.\" Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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: head/share/man/man5/bluetooth.device.conf.5 267776 2014-06-23 08:27:27Z bapt $
+.\"
+.Dd May 27, 2008
+.Dt BLUETOOTH.DEVICE.CONF 5
+.Os
+.Sh NAME
+.Nm bluetooth.device.conf
+.Nd Bluetooth device configuration file
+.Sh DESCRIPTION
+Bluetooth device configuration framework provides ability to adjust certain
+Bluetooth device parameters on per-device basis.
+.Pp
+Bluetooth device configuration files are plain text files that should conform
+to basic
+.Xr sh 1
+syntax.
+Even though Bluetooth device are not exactly shell scripts,
+they are parsed and passed through shell
+.Ic eval
+command.
+This makes it possible to use various shell tricks in the Bluetooth device
+configuration files.
+.Pp
+The
+.Pa /etc/rc.d/bluetooth
+script is used to start and stop Bluetooth devices.
+This script is not executed by default when system boots.
+It is called by
+.Xr devd 8
+in response to Bluetooth device arrival and departure events.
+It is possible to execute this script by hand if required.
+The script accepts Bluetooth device driver name as an extra parameter.
+.Pp
+The system wide Bluetooth device configuration file is called
+.Pa /etc/defaults/\:bluetooth.device.conf .
+Configuration parameters set in the system wide Bluetooth device configuration
+file apply to every Bluetooth device connected to the system.
+.Pp
+Configuration parameters overrides for the specific Bluetooth device
+should be placed in the
+.Pa /etc/bluetooth/ Ns Ar DEVICE_DRIVER_NAME Ns Pa .conf
+file.
+Where
+.Ar DEVICE_DRIVER_NAME
+is the device driver name of the Bluetooth device.
+.Pp
+The following list provides a name and short description for each
+variable that can be set in a Bluetooth device configuration file.
+.Bl -tag -width indent-two
+.It Va authentication_enable
+.Pq Vt bool
+The
+.Va authentication_enable
+parameter controls if the device requires to authenticate the remote device
+at connection setup.
+If set to
+.Dq Li YES ,
+the device will try to authenticate the other device at connection setup.
+Bluetooth authentication requests are handled by
+.Xr hcsecd 8
+daemon.
+.It Va class
+.Pq Vt str
+The
+.Va class
+parameter is used to indicate the capabilities of the device to
+other devices.
+For more details see
+.Dq Assigned Numbers - Bluetooth Baseband
+document.
+.It Va connectable
+.Pq Vt bool
+The
+.Va connectable
+parameter controls whether or not the device should periodically scan for
+page attempts from other devices.
+If set to
+.Dq Li YES ,
+the device will periodically scan for page attempts from other devices.
+.It Va discoverable
+.Pq Vt bool
+The
+.Va discoverable
+parameter controls whether or not the device should periodically scan for
+inquiry requests from other devices.
+If set to
+.Dq Li YES ,
+the device will periodically scan for inquiry requests from other devices.
+.It Va encryption_mode
+.Pq Vt str
+The
+.Va encryption_mode
+parameter controls if the device requires encryption to the remote device
+at connection setup.
+At connection setup, only the devices with the
+.Va authentication_enable
+parameter enabled and
+.Va encryption_mode
+parameter enabled will try to encrypt the connection to the other device.
+Possible values are
+.Dq Li NONE
+encryption disabled,
+.Dq Li P2P
+encryption for only point-to-point packets,
+or
+.Dq Li ALL
+encryption for both point-to-point and broadcast packets.
+.It Va hci_debug_level
+.Pq Vt int
+HCI node debug level.
+Higher values mean more verbose output.
+.It Va l2cap_debug_level
+.Pq Vt int
+L2CAP node debug level.
+Higher values mean more verbose output.
+.It Va local_name
+.Pq Vt str
+The
+.Va local_name
+parameter provides the ability to modify the user friendly name for the device.
+.It Va role_switch
+.Pq Vt bool
+The
+.Va role_switch
+parameter controls whether the local device should perform role switch.
+By default, if role switch is supported, the local device will try to perform
+role switch and become Master on incoming connection.
+Some devices do not support role switch and thus incoming connections from
+such devices will fail.
+If
+.Va role switch
+is disabled then accepting device will remain Slave.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/defaults/bluetooth.device.conf" -compact
+.It Pa /etc/defaults/bluetooth.device.conf
+.It Pa /etc/rc.d/bluetooth
+.El
+.Sh EXAMPLES
+The
+.Pa /etc/bluetooth/ubt0.conf
+file should be used to specify configuration parameters overrides for the
+first USB Bluetooth device
+(device driver name is
+.Li ubt0 ) .
+.Pp
+The
+.Pa /etc/bluetooth/ubt1.conf
+file should be used to specify configuration parameters overrides for the
+second USB Bluetooth device.
+.Sh SEE ALSO
+.Xr ng_bt3c 4 ,
+.Xr ng_h4 4 ,
+.Xr ng_hci 4 ,
+.Xr ng_l2cap 4 ,
+.Xr ng_ubt 4 ,
+.Xr devd 8 ,
+.Xr hccontrol 8 ,
+.Xr hcsecd 8 ,
+.Xr l2control 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
diff --git a/share/man/man5/bluetooth.hosts.5 b/share/man/man5/bluetooth.hosts.5
new file mode 100644
index 0000000000..65d134c9c3
--- /dev/null
+++ b/share/man/man5/bluetooth.hosts.5
@@ -0,0 +1,63 @@
+.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: bluetooth.hosts.5,v 1.5 2003/05/20 22:52:39 max Exp $
+.\" $FreeBSD: head/share/man/man5/bluetooth.hosts.5 267776 2014-06-23 08:27:27Z bapt $
+.\"
+.Dd May 8, 2003
+.Dt BLUETOOTH.HOSTS 5
+.Os
+.Sh NAME
+.Nm bluetooth.hosts
+.Nd Bluetooth host name database
+.Sh DESCRIPTION
+The
+.Pa /etc/bluetooth/hosts
+file contains information regarding the known Bluetooth hosts.
+For each Bluetooth host a single line should be present with the
+following information:
+.Bd -unfilled -offset indent
+Bluetooth address
+official host name
+aliases
+.Ed
+.Pp
+Items are separated by any number of blanks and/or tab characters.
+A
+.Ql #
+indicates the beginning of a comment; characters up to the end of the line are
+not interpreted by routines which search the file.
+.Pp
+Bluetooth addresses are specified as six hex bytes separated by columns
+(BD_ADDR).
+Host names may contain any printable character other than a field
+delimiter, newline, or comment character.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/bluetooth/hosts" -compact
+.It Pa /etc/bluetooth/hosts
+.El
+.Sh SEE ALSO
+.Xr bluetooth 3
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
diff --git a/share/man/man5/bluetooth.protocols.5 b/share/man/man5/bluetooth.protocols.5
new file mode 100644
index 0000000000..8f2aaf10a3
--- /dev/null
+++ b/share/man/man5/bluetooth.protocols.5
@@ -0,0 +1,62 @@
+.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: bluetooth.protocols.5,v 1.1 2003/05/20 22:52:39 max Exp $
+.\" $FreeBSD: head/share/man/man5/bluetooth.protocols.5 267776 2014-06-23 08:27:27Z bapt $
+.\"
+.Dd May 8, 2003
+.Dt BLUETOOTH.PROTOCOLS 5
+.Os
+.Sh NAME
+.Nm bluetooth.protocols
+.Nd Bluetooth Protocol Service Multiplexor database
+.Sh DESCRIPTION
+The
+.Pa /etc/bluetooth/protocols
+file contains information regarding the known Bluetooth Protocol Service
+Multiplexor values.
+For each Bluetooth Protocol Service Multiplexor a single line should be
+present with the following information:
+.Bd -unfilled -offset indent
+official Protocol Service Multiplexor name
+official Protocol Service Multiplexor value
+aliases
+.Ed
+.Pp
+Items are separated by any number of blanks and/or tab characters.
+A
+.Ql #
+indicates the beginning of a comment; characters up to the end of the line are
+not interpreted by routines which search the file.
+.Pp
+Bluetooth Protocol Service Multiplexor names may contain any printable
+character other than a field delimiter, newline, or comment character.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/bluetooth/hosts" -compact
+.It Pa /etc/bluetooth/protocols
+.El
+.Sh SEE ALSO
+.Xr bluetooth 3
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
diff --git a/share/man/man5/rc.conf.5 b/share/man/man5/rc.conf.5
index 14212291de..fb55521c4b 100644
--- a/share/man/man5/rc.conf.5
+++ b/share/man/man5/rc.conf.5
@@ -1405,67 +1405,128 @@ is set to
 these are the flags to pass to the
 .Xr dntpd 8
 daemon.
-.It Va btconfig_enable
+.It Va hcsecd_enable
 .Pq Vt bool
 If set to
 .Dq Li YES ,
-configure Bluetooth devices via
-.Xr btconfig 8
-at system boot time.
-.It Va btconfig_devices
+enable Bluetooth security daemon.
+.It Va hcsecd_config
 .Pq Vt str
-If
-.Va btconfig_enable
-is set to
-.Dq Li YES ,
-this is the list of Bluetooth devices to configure.
-If
-.Va btconfig_devices
-is not specified, all devices known to the system will be configured.
-A
-.Va btconfig_ Ns Aq Ar device
-variable can be set to specify parameters to be passed to
-.Ar device .
-.It Va btconfig_args
-.Pq Vt str
-If
-.Va btconfig_enable
-is set to
-.Dq Li YES ,
-this is the list of configuration parameters to pass to all Bluetooth
-devices.
+Configuration file for
+.Xr hcsecd 8 .
+Default
+.Pa /etc/bluetooth/hcsecd.conf .
 .It Va sdpd_enable
 .Pq Vt bool
 If set to
 .Dq Li YES ,
-run the Service Discovery Profile daemon
-.Xr ( sdpd 8 )
-at system boot time.
-.It Va sdpd_flags
+enable Bluetooth Service Discovery Protocol daemon.
+.It Va sdpd_control
 .Pq Vt str
-If
-.Va sdpd_enable
-is set to
-.Dq Li YES ,
-these are the flags to pass to the
+Path to
 .Xr sdpd 8
-daemon.
-.It Va bthcid_enable
+control socket.
+Default
+.Pa /var/run/sdp .
+.It Va sdpd_groupname
+.Pq Vt str
+Sets
+.Xr sdpd 8
+group to run as after it initializes.
+Default
+.Dq Li nobody .
+.It Va sdpd_username
+.Pq Vt str
+Sets
+.Xr sdpd 8
+user to run as after it initializes.
+Default
+.Dq Li nobody .
+.It Va bthidd_enable
 .Pq Vt bool
 If set to
 .Dq Li YES ,
-run the Bluetooth Link Key/PIN Code Manager daemon
-.Xr ( bthcid 8 )
-at system boot time.
-.It Va bthcid_flags
+enable Bluetooth Human Interface Device daemon.
+.It Va bthidd_config
 .Pq Vt str
-If
-.Va bthcid_enable
-is set to
+Configuration file for
+.Xr bthidd 8 .
+Default
+.Pa /etc/bluetooth/bthidd.conf .
+.It Va bthidd_hids
+.Pq Vt str
+Path to a file, where
+.Xr bthidd 8
+will store information about known HID devices.
+Default
+.Pa /var/db/bthidd.hids .
+.It Va rfcomm_pppd_server_enable
+.Pq Vt bool
+If set to
 .Dq Li YES ,
-these are the flags to pass to the
-.Xr bthcid 8
-daemon.
+enable Bluetooth RFCOMM PPP wrapper daemon.
+.It Va rfcomm_pppd_server_profile
+.Pq Vt str
+The name of the profile to use from
+.Pa /etc/ppp/ppp.conf .
+Multiple profiles can be specified here.
+Also used to specify per-profile overrides.
+When the profile name contains any of the characters
+.Dq Li .-/+
+they are translated to
+.Dq Li _
+for the proposes of the override variable names.
+.It Va rfcomm_pppd_server_ Ns Ao Ar profile Ac Ns _bdaddr
+.Pq Vt str
+Overrides local address to listen on.
+By default
+.Xr rfcomm_pppd 8
+will listen on
+.Dq Li ANY
+address.
+The address can be specified as BD_ADDR or name.
+.It Va rfcomm_pppd_server_ Ns Ao Ar profile Ac Ns _channel
+.Pq Vt str
+Overrides local RFCOMM channel to listen on.
+By default
+.Xr rfcomm_pppd 8
+will listen on RFCOMM channel 1.
+Must set properly if multiple profiles used in the same time.
+.It Va rfcomm_pppd_server_ Ns Ao Ar profile Ac Ns _register_sp
+.Pq Vt bool
+Tells
+.Xr rfcomm_pppd 8
+if it should register Serial Port service on the specified RFCOMM channel.
+Default
+.Dq Li NO .
+.It Va rfcomm_pppd_server_ Ns Ao Ar profile Ac Ns _register_dun
+.Pq Vt bool
+Tells
+.Xr rfcomm_pppd 8
+if it should register Dial-Up Networking service on the specified
+RFCOMM channel.
+Default
+.Dq Li NO .
+.It Va ubthidhci_enable
+.Pq Vt bool
+If set to
+.Dq Li YES ,
+change the USB Bluetooth controller from HID mode to HCI mode.
+You also need to specify the location of USB Bluetooth controller with the
+.Va ubthidhci_busnum
+and
+.Va ubthidhci_addr
+variables.
+.It Va ubthidhci_busnum
+Bus number where the USB Bluetooth controller is located.
+Check the output of
+.Xr usbconfig 8
+on your system to find this information.
+.It Va ubthidhci_addr
+Bus address of the USB Bluetooth controller.
+Check the output of
+.Xr usbconfig 8
+on your system to find this information.
 .It Va nis_client_enable
 .Pq Vt bool
 If set to
@@ -2753,14 +2814,14 @@ By default no flags are passed.
 .Xr automount 8 ,
 .Xr automountd 8 ,
 .Xr autounmountd 8 ,
-.Xr btconfig 8 ,
-.Xr bthcid 8 ,
+.Xr bthidd 8 ,
 .Xr cron 8 ,
 .Xr devd 8 ,
 .Xr dhclient 8 ,
 .Xr dhcpcd 8 ,
 .Xr dntpd 8 ,
 .Xr ftpd 8 ,
+.Xr hcsecd 8 ,
 .Xr ifconfig 8 ,
 .Xr inetd 8 ,
 .Xr ip6addrctl 8 ,
@@ -2782,6 +2843,7 @@ By default no flags are passed.
 .Xr rndcontrol 8 ,
 .Xr route 8 ,
 .Xr routed 8 ,
+.Xr rfcomm_pppd 8 ,
 .Xr rpcbind 8 ,
 .Xr rpc.lockd 8 ,
 .Xr rpc.statd 8 ,
diff --git a/sys/Makefile b/sys/Makefile
index f0bb239cdd..f50168b884 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -11,7 +11,7 @@ SUBDIR=	boot
 .if defined(MODULES_OVERRIDE)
 SUBDIR+=${MODULES_OVERRIDE}
 .else
-SUBDIR+=bus crypto dev emulation gnu kern net netbt netproto vfs
+SUBDIR+=bus crypto dev emulation gnu kern net netproto vfs
 .if defined(WANT_NETGRAPH7)
 SUBDIR+=netgraph7
 .else
diff --git a/sys/Makefile.modules b/sys/Makefile.modules
index afacc19c91..b6311f7d13 100644
--- a/sys/Makefile.modules
+++ b/sys/Makefile.modules
@@ -7,7 +7,7 @@ SUBDIR=${MODULES_OVERRIDE}
 .if ${MACHINE_PLATFORM} != "vkernel64"
 SUBDIR=bus
 .endif
-SUBDIR+=crypto emulation dev gnu kern net netbt netproto vfs
+SUBDIR+=crypto emulation dev gnu kern net netproto vfs
 .if defined(WANT_NETGRAPH7)
 SUBDIR+=netgraph7
 .else
diff --git a/sys/conf/files b/sys/conf/files
index 6966aeac95..63417beb93 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1584,25 +1584,6 @@ net/raw_cb.c		standard
 net/raw_usrreq.c	standard
 net/route.c		standard
 net/rtsock.c		standard
-netbt/bt_input.c	optional bluetooth
-netbt/bt_proto.c	optional bluetooth
-netbt/hci_event.c	optional bluetooth
-netbt/hci_ioctl.c	optional bluetooth
-netbt/hci_link.c	optional bluetooth
-netbt/hci_misc.c	optional bluetooth
-netbt/hci_socket.c	optional bluetooth
-netbt/hci_unit.c	optional bluetooth
-netbt/l2cap_lower.c	optional bluetooth
-netbt/l2cap_misc.c	optional bluetooth
-netbt/l2cap_signal.c	optional bluetooth
-netbt/l2cap_socket.c	optional bluetooth
-netbt/l2cap_upper.c	optional bluetooth
-netbt/rfcomm_dlc.c	optional bluetooth
-netbt/rfcomm_session.c	optional bluetooth
-netbt/rfcomm_socket.c	optional bluetooth
-netbt/rfcomm_upper.c	optional bluetooth
-netbt/sco_socket.c	optional bluetooth
-netbt/sco_upper.c	optional bluetooth
 netproto/802_11/wlan/ieee80211.c            optional wlan
 netproto/802_11/wlan_acl/ieee80211_acl.c    optional wlan_acl
 netproto/802_11/wlan/ieee80211_action.c     optional wlan
diff --git a/sys/config/LINT64 b/sys/config/LINT64
index 05f079579b..b90fed37bd 100644
--- a/sys/config/LINT64
+++ b/sys/config/LINT64
@@ -1150,9 +1150,6 @@ device		iwnfw
 device		ralfw
 device		wpifw
 
-# Bluetooth Protocols
-device		bluetooth
-
 # Sound drivers
 #
 
diff --git a/sys/netbt/Makefile b/sys/netbt/Makefile
deleted file mode 100644
index a2fa0481e6..0000000000
--- a/sys/netbt/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-KMOD	= netbt
-SRCS	= sco_socket.c sco_upper.c bt_input.c bt_proto.c hci_event.c hci_ioctl.c
-SRCS	+= hci_link.c hci_misc.c hci_socket.c hci_unit.c l2cap_lower.c
-SRCS	+= l2cap_misc.c l2cap_signal.c l2cap_socket.c l2cap_upper.c
-SRCS	+= rfcomm_dlc.c rfcomm_session.c rfcomm_socket.c rfcomm_upper.c
-SRCS	+= device_if.h bus_if.h
-
-.include <bsd.kmod.mk>
-
-
diff --git a/sys/netbt/bluetooth.h b/sys/netbt/bluetooth.h
deleted file mode 100644
index 54cd927c96..0000000000
--- a/sys/netbt/bluetooth.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/* $DragonFly: src/sys/netbt/bluetooth.h,v 1.2 2008/03/18 13:41:42 hasso Exp $ */
-/* $OpenBSD: src/sys/netbt/bluetooth.h,v 1.5 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: bluetooth.h,v 1.6 2007/09/17 01:23:17 rillig Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
-
-#ifndef _NETBT_BLUETOOTH_H_
-#define _NETBT_BLUETOOTH_H_
-
-#include <sys/socket.h>
-#include <sys/types.h>
-
-/*
- * Bluetooth Address Family Protocol Numbers
- */
-#define BTPROTO_HCI	1
-#define BTPROTO_L2CAP	2
-#define BTPROTO_RFCOMM	3
-#define BTPROTO_SCO	4
-
-/* All sizes are in bytes */
-#define BLUETOOTH_BDADDR_SIZE	6
-
-/*
- * Bluetooth device address
- */
-typedef struct {
-	uint8_t	b[BLUETOOTH_BDADDR_SIZE];
-} __attribute__ ((packed)) bdaddr_t;
-
-/*
- * bdaddr utility functions
- */
-static __inline int
-bdaddr_same(const bdaddr_t *a, const bdaddr_t *b)
-{
-
-	return (a->b[0] == b->b[0] && a->b[1] == b->b[1]
-		&& a->b[2] == b->b[2] && a->b[3] == b->b[3]
-		&& a->b[4] == b->b[4] && a->b[5] == b->b[5]);
-}
-
-static __inline int
-bdaddr_any(const bdaddr_t *a)
-{
-
-	return (a->b[0] == 0 && a->b[1] == 0 && a->b[2] == 0
-		&& a->b[3] == 0 && a->b[4] == 0 && a->b[5] == 0);
-}
-
-static __inline void
-bdaddr_copy(bdaddr_t *d, const bdaddr_t *s)
-{
-
-	d->b[0] = s->b[0];
-	d->b[1] = s->b[1];
-	d->b[2] = s->b[2];
-	d->b[3] = s->b[3];
-	d->b[4] = s->b[4];
-	d->b[5] = s->b[5];
-}
-
-/*
- * Socket address used by Bluetooth protocols
- */
-struct sockaddr_bt {
-	uint8_t		bt_len;
-	sa_family_t	bt_family;
-	bdaddr_t	bt_bdaddr;
-	uint16_t	bt_psm;
-	uint8_t		bt_channel;
-	uint8_t		bt_zero[5];
-};
-
-/* Note: this is actually 6 bytes including terminator */
-#define BDADDR_ANY	((const bdaddr_t *) "\000\000\000\000\000")
-
-#ifdef _KERNEL
-#include <sys/bus.h>
-
-#ifdef MALLOC_DECLARE
-MALLOC_DECLARE(M_BLUETOOTH);
-#endif
-
-/*
- * Bluetooth Protocol API callback methods
- */
-struct mbuf;
-struct btproto {
-	void (*connecting)(void *);
-	void (*connected)(void *);
-	void (*disconnected)(void *, int);
-	void *(*newconn)(void *, struct sockaddr_bt *, struct sockaddr_bt *);
-	void (*complete)(void *, int);
-	void (*linkmode)(void *, int);
-	void (*input)(void *, struct mbuf *);
-};
-
-/*
- * Debugging stuff
- */
-#ifdef BLUETOOTH_DEBUG
-extern int bluetooth_debug;
-# define DPRINTF(fmt, args...)	do {			\
-	if (bluetooth_debug)				\
-		kprintf("%s: "fmt, __func__ , ##args);	\
-} while (/* CONSTCOND */0)
-
-# define DPRINTFN(n, fmt, args...)	do {		\
-	if (bluetooth_debug > (n))			\
-		kprintf("%s: "fmt, __func__ , ##args);	\
-} while (/* CONSTCOND */0)
-
-# define UNKNOWN(value)			\
-		kprintf("%s: %s = %d unknown!\n", __func__, #value, (value));
-#else
-# define DPRINTF(...) ((void)0)
-# define DPRINTFN(...) ((void)0)
-# define UNKNOWN(x) ((void)0)
-#endif	/* BLUETOOTH_DEBUG */
-
-#define sbspace(sb) \
-    ((long) imin((int)((sb)->ssb_hiwat - (sb)->ssb_cc), \
-         (int)((sb)->ssb_mbmax - (sb)->ssb_mbcnt)))
-#endif	/* _KERNEL */
-
-#define letoh16(x)              le16toh(x)
-#define letoh32(x)              le32toh(x)
-
-#endif	/* _NETBT_BLUETOOTH_H_ */
diff --git a/sys/netbt/bt_input.c b/sys/netbt/bt_input.c
deleted file mode 100644
index 3e580b0a80..0000000000
--- a/sys/netbt/bt_input.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/* $DragonFly: src/sys/netbt/bt_input.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */
-/* $OpenBSD: bt_input.c,v 1.5 2007/06/24 20:55:27 uwe Exp $ */
-
-/*
- * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-#include <sys/bus.h>
-
-#include <net/netisr.h>
-
-#include <sys/mplock2.h>
-
-#include <netbt/hci.h>
-
-void
-btintr(netmsg_t msg)
-{
-	struct hci_unit *unit;
-
-	get_mplock();
-	TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
-		hci_intr(unit);
-	}
-	rel_mplock();
-}
diff --git a/sys/netbt/bt_proto.c b/sys/netbt/bt_proto.c
deleted file mode 100644
index 88a6f1ee8a..0000000000
--- a/sys/netbt/bt_proto.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/* $OpenBSD: bt_proto.c,v 1.4 2007/06/24 20:55:27 uwe Exp $ */
-
-/*
- * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/param.h>
-#include <sys/domain.h>
-#include <sys/protosw.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/queue.h>
-#include <sys/kernel.h>
-#include <sys/mbuf.h>
-#include <sys/sysctl.h>
-#include <sys/bus.h>
-#include <sys/malloc.h>
-#include <net/if.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-#include <netbt/rfcomm.h>
-#include <netbt/sco.h>
-
-MALLOC_DEFINE(M_BLUETOOTH, "Bluetooth", "Bluetooth system memory");
-
-extern struct pr_usrreqs hci_usrreqs;
-
-static int
-netbt_modevent(module_t mod, int type, void *data)
-{
-	switch (type) {
-	case MOD_LOAD:
-		break;
-	case MOD_UNLOAD:
-		return EBUSY;
-		break;
-	default:
-		break;
-	}
-	return 0;
-}
-
-static moduledata_t netbt_mod = {
-	"netbt",
-	netbt_modevent,
-	NULL
-};
-
-DECLARE_MODULE(netbt, netbt_mod, SI_SUB_EXEC, SI_ORDER_ANY);
-MODULE_VERSION(netbt, 1);
-
-struct domain btdomain;
-
-struct protosw btsw[] = {
-	{ /* raw HCI commands */
-		.pr_type = SOCK_RAW,
-		.pr_domain = &btdomain,
-		.pr_protocol = BTPROTO_HCI,
-		.pr_flags = (PR_ADDR | PR_ATOMIC),
-		.pr_input = 0,
-		.pr_output = 0,
-		.pr_ctlinput = 0,
-		.pr_ctloutput = hci_ctloutput,
-		.pr_ctlport = NULL,
-		.pr_init = 0,
-		.pr_drain = 0,
-		.pr_usrreqs = &hci_usrreqs
-	},
-	{ /* HCI SCO data (audio) */
-		.pr_type = SOCK_SEQPACKET,
-		.pr_domain = &btdomain,
-		.pr_protocol = BTPROTO_SCO,
-		.pr_flags = (PR_CONNREQUIRED | PR_ATOMIC ),
-		.pr_input = 0,
-		.pr_output = 0,
-		.pr_ctlinput = 0,
-		.pr_ctloutput = sco_ctloutput,
-		.pr_ctlport = NULL,
-		.pr_init = 0,
-		.pr_drain = 0,
-		.pr_usrreqs = &sco_usrreqs
-
-	},
-	{ /* L2CAP Connection Oriented */
-		.pr_type = SOCK_SEQPACKET,
-		.pr_domain = &btdomain,
-		.pr_protocol = BTPROTO_L2CAP,
-		.pr_flags = (PR_CONNREQUIRED | PR_ATOMIC ),
-		.pr_input = 0,
-		.pr_output = 0,
-		.pr_ctlinput = 0,
-		.pr_ctloutput = l2cap_ctloutput,
-		.pr_ctlport = NULL,
-		.pr_init = 0,
-		.pr_drain = 0,
-		.pr_usrreqs = &l2cap_usrreqs
-	},
-	{ /* RFCOMM */
-		.pr_type = SOCK_STREAM,
-		.pr_domain = &btdomain,
-		.pr_protocol = BTPROTO_RFCOMM,
-		.pr_flags = (PR_CONNREQUIRED | PR_WANTRCVD),
-		.pr_input = 0,
-		.pr_output = 0,
-		.pr_ctlinput = 0,
-		.pr_ctloutput = rfcomm_ctloutput,
-		.pr_ctlport = NULL,
-		.pr_init = 0,
-		.pr_drain = 0,
-		.pr_usrreqs = &rfcomm_usrreqs
-	},
-};
-
-static void
-netbt_dispose(struct mbuf* m)
-{
-	zdestroy(l2cap_pdu_pool);
-	zdestroy(l2cap_req_pool);
-	zdestroy(rfcomm_credit_pool);
-}
-
-static void
-netbt_init(void)
-{
-	l2cap_pdu_pool = zinit("l2cap_pdu", sizeof(struct l2cap_pdu), 1,
-			       ZONE_DESTROYABLE);
-	if (l2cap_pdu_pool == NULL)
-		goto fail;
-	l2cap_req_pool = zinit("l2cap_req", sizeof(struct l2cap_req), 1,
-			       ZONE_DESTROYABLE);
-	if (l2cap_req_pool == NULL)
-		goto fail;
-	rfcomm_credit_pool = zinit("rfcomm_credit",
-				   sizeof(struct rfcomm_credit), 1,
-				   ZONE_DESTROYABLE);
-	if (rfcomm_credit_pool == NULL)
-		goto fail;
-	return;
-fail:
-	netbt_dispose(NULL);
-	panic("Can't create vm_zones");
-}
-
-struct domain btdomain = {
-	.dom_family = AF_BLUETOOTH,
-	.dom_name = "bluetooth",
-	.dom_init = netbt_init,
-	.dom_externalize = NULL,
-	.dom_dispose = netbt_dispose,
-	.dom_protosw = btsw,
-	.dom_protoswNPROTOSW = &btsw[NELEM(btsw)],
-	.dom_next = SLIST_ENTRY_INITIALIZER,
-	.dom_rtattach = 0,
-	.dom_rtoffset = 32,
-	.dom_maxrtkey = sizeof(struct sockaddr_bt),
-	.dom_ifattach = 0,
-	.dom_ifdetach = 0,
-};
-
-DOMAIN_SET(bt);
-SYSCTL_NODE(_net, OID_AUTO, bluetooth, CTLFLAG_RD, 0,
-    "Bluetooth Protocol Family");
-
-/* HCI sysctls */
-SYSCTL_NODE(_net_bluetooth, OID_AUTO, hci, CTLFLAG_RD, 0,
-    "Host Controller Interface");
-SYSCTL_INT(_net_bluetooth_hci, OID_AUTO, sendspace, CTLFLAG_RW, &hci_sendspace,
-    0, "Socket Send Buffer Size");
-SYSCTL_INT(_net_bluetooth_hci, OID_AUTO, recvspace, CTLFLAG_RW, &hci_recvspace,
-    0, "Socket Receive Buffer Size");
-SYSCTL_INT(_net_bluetooth_hci, OID_AUTO, acl_expiry, CTLFLAG_RW,
-    &hci_acl_expiry, 0, "ACL Connection Expiry Time");
-SYSCTL_INT(_net_bluetooth_hci, OID_AUTO, memo_expiry, CTLFLAG_RW,
-    &hci_memo_expiry, 0, "Memo Expiry Time");
-SYSCTL_INT(_net_bluetooth_hci, OID_AUTO, eventq_max, CTLFLAG_RW,
-    &hci_eventq_max, 0, "Max Event queue length");
-SYSCTL_INT(_net_bluetooth_hci, OID_AUTO, aclrxq_max, CTLFLAG_RW,
-    &hci_aclrxq_max, 0, "Max ACL rx queue length");
-SYSCTL_INT(_net_bluetooth_hci, OID_AUTO, scorxq_max, CTLFLAG_RW,
-    &hci_scorxq_max, 0, "Max SCO rx queue length");
-
-/* L2CAP sysctls */
-SYSCTL_NODE(_net_bluetooth, OID_AUTO, l2cap, CTLFLAG_RD, 0,
-    "Logical Link Control & Adaptation Protocol");
-SYSCTL_INT(_net_bluetooth_l2cap, OID_AUTO, sendspace, CTLFLAG_RW,
-    &l2cap_sendspace, 0, "Socket Send Buffer Size");
-SYSCTL_INT(_net_bluetooth_l2cap, OID_AUTO, recvspace, CTLFLAG_RW,
-    &l2cap_recvspace, 0, "Socket Receive Buffer Size");
-SYSCTL_INT(_net_bluetooth_l2cap, OID_AUTO, rtx, CTLFLAG_RW,
-    &l2cap_response_timeout, 0, "Response Timeout");
-SYSCTL_INT(_net_bluetooth_l2cap, OID_AUTO, ertx, CTLFLAG_RW,
-    &l2cap_response_extended_timeout, 0, "Extended Response Timeout");
-
-/* RFCOMM sysctls */
-SYSCTL_NODE(_net_bluetooth, OID_AUTO, rfcomm, CTLFLAG_RD, 0,
-    "Serial Cable Emulation");
-SYSCTL_INT(_net_bluetooth_rfcomm, OID_AUTO, sendspace, CTLFLAG_RW,
-    &rfcomm_sendspace, 0, "Socket Send Buffer Size");
-SYSCTL_INT(_net_bluetooth_rfcomm, OID_AUTO, recvspace, CTLFLAG_RW,
-    &rfcomm_recvspace, 0, "Socket Receive Buffer Size");
-SYSCTL_INT(_net_bluetooth_rfcomm, OID_AUTO, mtu_default, CTLFLAG_RW,
-    &rfcomm_mtu_default, 0, "Default MTU");
-SYSCTL_INT(_net_bluetooth_rfcomm, OID_AUTO, ack_timeout, CTLFLAG_RW,
-    &rfcomm_ack_timeout, 0, "Acknowledgement Timer");
-SYSCTL_INT(_net_bluetooth_rfcomm, OID_AUTO, mcc_timeout, CTLFLAG_RW,
-    &rfcomm_mcc_timeout, 0, "Response Timeout for Multiplexer Control Channel");
-
-/* SCO sysctls */
-SYSCTL_NODE(_net_bluetooth, OID_AUTO, sco, CTLFLAG_RD, 0, "SCO data");
-SYSCTL_INT(_net_bluetooth_sco, OID_AUTO, sendspace, CTLFLAG_RW, &sco_sendspace,
-    0, "Socket Send Buffer Size");
-SYSCTL_INT(_net_bluetooth_sco, OID_AUTO, recvspace, CTLFLAG_RW, &sco_recvspace,
-    0, "Socket Receive Buffer Size");
-
-static void
-netisr_netbt_setup(void *dummy __unused)
-{
-	netisr_register(NETISR_BLUETOOTH, btintr, NULL);
-}
-
-SYSINIT(netbt_setup, SI_BOOT2_KLD, SI_ORDER_ANY, netisr_netbt_setup, NULL);
diff --git a/sys/netbt/hci.h b/sys/netbt/hci.h
deleted file mode 100644
index f1cb2a76b0..0000000000
--- a/sys/netbt/hci.h
+++ /dev/null
@@ -1,2579 +0,0 @@
-/* $DragonFly: src/sys/netbt/hci.h,v 1.2 2008/03/18 13:41:42 hasso Exp $ */
-/* $OpenBSD: src/sys/netbt/hci.h,v 1.10 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: hci.h,v 1.22 2008/02/10 17:40:54 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 Maksim Yevmenkin <m_evmenkin@yahoo.com>
- * 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.
- *
- * $Id: hci.h,v 1.22 2008/02/10 17:40:54 plunky Exp $
- * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_hci.h,v 1.6 2005/01/07 01:45:43 imp Exp $
- */
-
-/*
- * This file contains everything that applications need to know from
- * Host Controller Interface (HCI). Information taken from Bluetooth
- * Core Specifications (v1.1, v2.0 and v2.1)
- *
- * This file can be included by both kernel and userland applications.
- *
- * NOTE: Here and after Bluetooth device is called a "unit". Bluetooth
- *       specification refers to both devices and units. They are the
- *       same thing (I think), so to be consistent word "unit" will be
- *       used.
- */
-
-#ifndef _NETBT_HCI_H_
-#define _NETBT_HCI_H_
-
-#include <netbt/bluetooth.h>
-
-#include <sys/ioccom.h>
-#include <sys/lock.h>
-
-/**************************************************************************
- **************************************************************************
- **                   Common defines and types (HCI)
- **************************************************************************
- **************************************************************************/
-
-#define HCI_LAP_SIZE			3   /* unit LAP */
-#define HCI_KEY_SIZE			16  /* link key */
-#define HCI_PIN_SIZE			16  /* link PIN */
-#define HCI_EVENT_MASK_SIZE		8   /* event mask */
-#define HCI_CLASS_SIZE			3   /* unit class */
-#define HCI_FEATURES_SIZE		8   /* LMP features */
-#define HCI_UNIT_NAME_SIZE		248 /* unit name size */
-#define HCI_DEVNAME_SIZE		16  /* same as dv_xname */
-#define HCI_COMMANDS_SIZE		64  /* supported commands mask */
-
-/* HCI specification */
-#define HCI_SPEC_V10			0x00 /* v1.0 */
-#define HCI_SPEC_V11			0x01 /* v1.1 */
-#define HCI_SPEC_V12			0x02 /* v1.2 */
-#define HCI_SPEC_V20			0x03 /* v2.0 */
-#define HCI_SPEC_V21			0x04 /* v2.1 */
-/* 0x05 - 0xFF - reserved for future use */
-
-/* LMP features (and page 0 of extended features) */
-/* ------------------- byte 0 --------------------*/
-#define HCI_LMP_3SLOT			0x01
-#define HCI_LMP_5SLOT			0x02
-#define HCI_LMP_ENCRYPTION		0x04
-#define HCI_LMP_SLOT_OFFSET		0x08
-#define HCI_LMP_TIMIACCURACY		0x10
-#define HCI_LMP_ROLE_SWITCH		0x20
-#define HCI_LMP_HOLD_MODE		0x40
-#define HCI_LMP_SNIFF_MODE		0x80
-/* ------------------- byte 1 --------------------*/
-#define HCI_LMP_PARK_MODE		0x01
-#define HCI_LMP_RSSI			0x02
-#define HCI_LMP_CHANNEL_QUALITY		0x04
-#define HCI_LMP_SCO_LINK		0x08
-#define HCI_LMP_HV2_PKT			0x10
-#define HCI_LMP_HV3_PKT			0x20
-#define HCI_LMP_ULAW_LOG		0x40
-#define HCI_LMP_ALAW_LOG		0x80
-/* ------------------- byte 2 --------------------*/
-#define HCI_LMP_CVSD			0x01
-#define HCI_LMP_PAGISCHEME		0x02
-#define HCI_LMP_POWER_CONTROL		0x04
-#define HCI_LMP_TRANSPARENT_SCO		0x08
-#define HCI_LMP_FLOW_CONTROL_LAG0	0x10
-#define HCI_LMP_FLOW_CONTROL_LAG1	0x20
-#define HCI_LMP_FLOW_CONTROL_LAG2	0x40
-#define HCI_LMP_BC_ENCRYPTION		0x80
-/* ------------------- byte 3 --------------------*/
-/* reserved				0x01 */
-#define HCI_LMP_EDR_ACL_2MBPS		0x02
-#define HCI_LMP_EDR_ACL_3MBPS		0x04
-#define HCI_LMP_ENHANCED_ISCAN		0x08
-#define HCI_LMP_INTERLACED_ISCAN	0x10
-#define HCI_LMP_INTERLACED_PSCAN	0x20
-#define HCI_LMP_RSSI_INQUIRY		0x40
-#define HCI_LMP_EV3_PKT			0x80
-/* ------------------- byte 4 --------------------*/
-#define HCI_LMP_EV4_PKT			0x01
-#define HCI_LMP_EV5_PKT			0x02
-/* reserved				0x04 */
-#define HCI_LMP_AFH_CAPABLE_SLAVE	0x08
-#define HCI_LMP_AFH_CLASS_SLAVE		0x10
-/* reserved				0x20 */
-/* reserved				0x40 */
-#define HCI_LMP_3SLOT_EDR_ACL		0x80
-/* ------------------- byte 5 --------------------*/
-#define HCI_LMP_5SLOT_EDR_ACL		0x01
-#define HCI_LMP_SNIFF_SUBRATING		0x02
-#define HCI_LMP_PAUSE_ENCRYPTION	0x04
-#define HCI_LMP_AFH_CAPABLE_MASTER	0x08
-#define HCI_LMP_AFH_CLASS_MASTER	0x10
-#define HCI_LMP_EDR_eSCO_2MBPS		0x20
-#define HCI_LMP_EDR_eSCO_3MBPS		0x40
-#define HCI_LMP_3SLOT_EDR_eSCO		0x80
-/* ------------------- byte 6 --------------------*/
-#define HCI_LMP_EXTENDED_INQUIRY	0x01
-/* reserved				0x02 */
-/* reserved				0x04 */
-#define HCI_LMP_SIMPLE_PAIRING		0x08
-#define HCI_LMP_ENCAPSULATED_PDU	0x10
-#define HCI_LMP_ERRDATA_REPORTING	0x20
-#define HCI_LMP_NOFLUSH_PB_FLAG		0x40
-/* reserved				0x80 */
-/* ------------------- byte 7 --------------------*/
-#define HCI_LMP_LINK_SUPERVISION_TO	0x01
-#define HCI_LMP_INQ_RSP_TX_POWER	0x02
-#define HCI_LMP_EXTENDED_FEATURES	0x80
-
-/* Link types */
-#define HCI_LINK_SCO			0x00 /* Voice */
-#define HCI_LINK_ACL			0x01 /* Data */
-#define HCI_LINK_eSCO			0x02 /* eSCO */
-/* 0x03 - 0xFF - reserved for future use */
-
-/*
- * ACL/SCO packet type bits are set to enable the
- * packet type, except for 2MBPS and 3MBPS when they
- * are unset to enable the packet type.
- */
-/* ACL Packet types for "Create Connection" */
-#define HCI_PKT_2MBPS_DH1	0x0002
-#define HCI_PKT_3MBPS_DH1	0x0004
-#define HCI_PKT_DM1		0x0008
-#define HCI_PKT_DH1		0x0010
-#define HCI_PKT_2MBPS_DH3	0x0100
-#define HCI_PKT_3MBPS_DH3	0x0200
-#define HCI_PKT_DM3		0x0400
-#define HCI_PKT_DH3		0x0800
-#define HCI_PKT_2MBPS_DH5	0x1000
-#define HCI_PKT_3MBPS_DH5	0x2000
-#define HCI_PKT_DM5		0x4000
-#define HCI_PKT_DH5		0x8000
-
-/* SCO Packet types for "Setup Synchronous Connection" */
-#define HCI_PKT_HV1		0x0001
-#define HCI_PKT_HV2		0x0002
-#define HCI_PKT_HV3		0x0004
-#define HCI_PKT_EV3		0x0008
-#define HCI_PKT_EV4		0x0010
-#define HCI_PKT_EV5		0x0020
-#define HCI_PKT_2MBPS_EV3	0x0040
-#define HCI_PKT_3MBPS_EV3	0x0080
-#define HCI_PKT_2MBPS_EV5	0x0100
-#define HCI_PKT_3MBPS_EV5	0x0200
-
-/*
- * Connection modes/Unit modes
- *
- * This is confusing. It means that one of the units change its mode
- * for the specific connection. For example one connection was put on
- * hold (but i could be wrong :)
- */
-
-/* Page scan modes (are deprecated) */
-#define HCI_MANDATORY_PAGE_SCAN_MODE		0x00
-#define HCI_OPTIONAL_PAGE_SCAN_MODE1		0x01
-#define HCI_OPTIONAL_PAGE_SCAN_MODE2		0x02
-#define HCI_OPTIONAL_PAGE_SCAN_MODE3		0x03
-/* 0x04 - 0xFF - reserved for future use */
-
-/* Page scan repetition modes */
-#define HCI_SCAN_REP_MODE0			0x00
-#define HCI_SCAN_REP_MODE1			0x01
-#define HCI_SCAN_REP_MODE2			0x02
-/* 0x03 - 0xFF - reserved for future use */
-
-/* Page scan period modes */
-#define HCI_PAGE_SCAN_PERIOD_MODE0		0x00
-#define HCI_PAGE_SCAN_PERIOD_MODE1		0x01
-#define HCI_PAGE_SCAN_PERIOD_MODE2		0x02
-/* 0x03 - 0xFF - reserved for future use */
-
-/* Scan enable */
-#define HCI_NO_SCAN_ENABLE			0x00
-#define HCI_INQUIRY_SCAN_ENABLE			0x01
-#define HCI_PAGE_SCAN_ENABLE			0x02
-/* 0x04 - 0xFF - reserved for future use */
-
-/* Hold mode activities */
-#define HCI_HOLD_MODE_NO_CHANGE			0x00
-#define HCI_HOLD_MODE_SUSPEND_PAGE_SCAN		0x01
-#define HCI_HOLD_MODE_SUSPEND_INQUIRY_SCAN	0x02
-#define HCI_HOLD_MODE_SUSPEND_PERIOD_INQUIRY	0x04
-/* 0x08 - 0x80 - reserved for future use */
-
-/* Connection roles */
-#define HCI_ROLE_MASTER				0x00
-#define HCI_ROLE_SLAVE				0x01
-/* 0x02 - 0xFF - reserved for future use */
-
-/* Key flags */
-#define HCI_USE_SEMI_PERMANENT_LINK_KEYS	0x00
-#define HCI_USE_TEMPORARY_LINK_KEY		0x01
-/* 0x02 - 0xFF - reserved for future use */
-
-/* Pin types */
-#define HCI_PIN_TYPE_VARIABLE			0x00
-#define HCI_PIN_TYPE_FIXED			0x01
-
-/* Link key types */
-#define HCI_LINK_KEY_TYPE_COMBINATION_KEY	0x00
-#define HCI_LINK_KEY_TYPE_LOCAL_UNIT_KEY	0x01
-#define HCI_LINK_KEY_TYPE_REMOTE_UNIT_KEY	0x02
-/* 0x03 - 0xFF - reserved for future use */
-
-/* Encryption modes */
-#define HCI_ENCRYPTION_MODE_NONE		0x00
-#define HCI_ENCRYPTION_MODE_P2P			0x01
-#define HCI_ENCRYPTION_MODE_ALL			0x02
-/* 0x03 - 0xFF - reserved for future use */
-
-/* Quality of service types */
-#define HCI_SERVICE_TYPE_NO_TRAFFIC		0x00
-#define HCI_SERVICE_TYPE_BEST_EFFORT		0x01
-#define HCI_SERVICE_TYPE_GUARANTEED		0x02
-/* 0x03 - 0xFF - reserved for future use */
-
-/* Link policy settings */
-#define HCI_LINK_POLICY_DISABLE_ALL_LM_MODES	0x0000
-#define HCI_LINK_POLICY_ENABLE_ROLE_SWITCH	0x0001 /* Master/Slave switch */
-#define HCI_LINK_POLICY_ENABLE_HOLD_MODE	0x0002
-#define HCI_LINK_POLICY_ENABLE_SNIFF_MODE	0x0004
-#define HCI_LINK_POLICY_ENABLE_PARK_MODE	0x0008
-/* 0x0010 - 0x8000 - reserved for future use */
-
-/* Event masks */
-#define HCI_EVMSK_ALL				0x00000000ffffffff
-#define HCI_EVMSK_NONE				0x0000000000000000
-#define HCI_EVMSK_INQUIRY_COMPL			0x0000000000000001
-#define HCI_EVMSK_INQUIRY_RESULT		0x0000000000000002
-#define HCI_EVMSK_CON_COMPL			0x0000000000000004
-#define HCI_EVMSK_CON_REQ			0x0000000000000008
-#define HCI_EVMSK_DISCON_COMPL			0x0000000000000010
-#define HCI_EVMSK_AUTH_COMPL			0x0000000000000020
-#define HCI_EVMSK_REMOTE_NAME_REQ_COMPL		0x0000000000000040
-#define HCI_EVMSK_ENCRYPTION_CHANGE		0x0000000000000080
-#define HCI_EVMSK_CHANGE_CON_LINK_KEY_COMPL	0x0000000000000100
-#define HCI_EVMSK_MASTER_LINK_KEY_COMPL		0x0000000000000200
-#define HCI_EVMSK_READ_REMOTE_FEATURES_COMPL	0x0000000000000400
-#define HCI_EVMSK_READ_REMOTE_VER_INFO_COMPL	0x0000000000000800
-#define HCI_EVMSK_QOS_SETUP_COMPL		0x0000000000001000
-#define HCI_EVMSK_COMMAND_COMPL			0x0000000000002000
-#define HCI_EVMSK_COMMAND_STATUS		0x0000000000004000
-#define HCI_EVMSK_HARDWARE_ERROR		0x0000000000008000
-#define HCI_EVMSK_FLUSH_OCCUR			0x0000000000010000
-#define HCI_EVMSK_ROLE_CHANGE			0x0000000000020000
-#define HCI_EVMSK_NUM_COMPL_PKTS		0x0000000000040000
-#define HCI_EVMSK_MODE_CHANGE			0x0000000000080000
-#define HCI_EVMSK_RETURN_LINK_KEYS		0x0000000000100000
-#define HCI_EVMSK_PIN_CODE_REQ			0x0000000000200000
-#define HCI_EVMSK_LINK_KEY_REQ			0x0000000000400000
-#define HCI_EVMSK_LINK_KEY_NOTIFICATION		0x0000000000800000
-#define HCI_EVMSK_LOOPBACK_COMMAND		0x0000000001000000
-#define HCI_EVMSK_DATA_BUFFER_OVERFLOW		0x0000000002000000
-#define HCI_EVMSK_MAX_SLOT_CHANGE		0x0000000004000000
-#define HCI_EVMSK_READ_CLOCK_OFFSET_COMLETE	0x0000000008000000
-#define HCI_EVMSK_CON_PKT_TYPE_CHANGED		0x0000000010000000
-#define HCI_EVMSK_QOS_VIOLATION			0x0000000020000000
-#define HCI_EVMSK_PAGE_SCAN_MODE_CHANGE		0x0000000040000000
-#define HCI_EVMSK_PAGE_SCAN_REP_MODE_CHANGE	0x0000000080000000
-/* 0x0000000100000000 - 0x8000000000000000 - reserved for future use */
-
-/* Filter types */
-#define HCI_FILTER_TYPE_NONE			0x00
-#define HCI_FILTER_TYPE_INQUIRY_RESULT		0x01
-#define HCI_FILTER_TYPE_CON_SETUP		0x02
-/* 0x03 - 0xFF - reserved for future use */
-
-/* Filter condition types for HCI_FILTER_TYPE_INQUIRY_RESULT */
-#define HCI_FILTER_COND_INQUIRY_NEW_UNIT	0x00
-#define HCI_FILTER_COND_INQUIRY_UNIT_CLASS	0x01
-#define HCI_FILTER_COND_INQUIRY_BDADDR		0x02
-/* 0x03 - 0xFF - reserved for future use */
-
-/* Filter condition types for HCI_FILTER_TYPE_CON_SETUP */
-#define HCI_FILTER_COND_CON_ANY_UNIT		0x00
-#define HCI_FILTER_COND_CON_UNIT_CLASS		0x01
-#define HCI_FILTER_COND_CON_BDADDR		0x02
-/* 0x03 - 0xFF - reserved for future use */
-
-/* Xmit level types */
-#define HCI_XMIT_LEVEL_CURRENT			0x00
-#define HCI_XMIT_LEVEL_MAXIMUM			0x01
-/* 0x02 - 0xFF - reserved for future use */
-
-/* Host Controller to Host flow control */
-#define HCI_HC2H_FLOW_CONTROL_NONE		0x00
-#define HCI_HC2H_FLOW_CONTROL_ACL		0x01
-#define HCI_HC2H_FLOW_CONTROL_SCO		0x02
-#define HCI_HC2H_FLOW_CONTROL_BOTH		0x03
-/* 0x04 - 0xFF - reserved future use */
-
-/* Loopback modes */
-#define HCI_LOOPBACK_NONE			0x00
-#define HCI_LOOPBACK_LOCAL			0x01
-#define HCI_LOOPBACK_REMOTE			0x02
-/* 0x03 - 0xFF - reserved future use */
-
-/**************************************************************************
- **************************************************************************
- **                 Link level defines, headers and types
- **************************************************************************
- **************************************************************************/
-
-/*
- * Macro(s) to combine OpCode and extract OGF (OpCode Group Field)
- * and OCF (OpCode Command Field) from OpCode.
- */
-
-#define HCI_OPCODE(gf,cf)		((((gf) & 0x3f) << 10) | ((cf) & 0x3ff))
-#define HCI_OCF(op)			((op) & 0x3ff)
-#define HCI_OGF(op)			(((op) >> 10) & 0x3f)
-
-/*
- * Macro(s) to extract/combine connection handle, BC (Broadcast) and
- * PB (Packet boundary) flags.
- */
-
-#define HCI_CON_HANDLE(h)		((h) & 0x0fff)
-#define HCI_PB_FLAG(h)			(((h) & 0x3000) >> 12)
-#define HCI_BC_FLAG(h)			(((h) & 0xc000) >> 14)
-#define HCI_MK_CON_HANDLE(h, pb, bc) \
-	(((h) & 0x0fff) | (((pb) & 3) << 12) | (((bc) & 3) << 14))
-
-/* PB flag values */
-					/* 00 - reserved for future use */
-#define	HCI_PACKET_FRAGMENT		0x1
-#define	HCI_PACKET_START		0x2
-					/* 11 - reserved for future use */
-
-/* BC flag values */
-#define HCI_POINT2POINT			0x0 /* only Host controller to Host */
-#define HCI_BROADCAST_ACTIVE		0x1 /* both directions */
-#define HCI_BROADCAST_PICONET		0x2 /* both directions */
-					/* 11 - reserved for future use */
-
-/* HCI command packet header */
-typedef struct {
-	uint8_t		type;	/* MUST be 0x01 */
-	uint16_t	opcode; /* OpCode */
-	uint8_t		length; /* parameter(s) length in bytes */
-} __attribute__ ((__packed__)) hci_cmd_hdr_t;
-
-#define HCI_CMD_PKT			0x01
-#define HCI_CMD_PKT_SIZE		(sizeof(hci_cmd_hdr_t) + 0xff)
-
-/* ACL data packet header */
-typedef struct {
-	uint8_t		type;	     /* MUST be 0x02 */
-	uint16_t	con_handle;  /* connection handle + PB + BC flags */
-	uint16_t	length;      /* payload length in bytes */
-} __attribute__ ((__packed__)) hci_acldata_hdr_t;
-
-#define HCI_ACL_DATA_PKT		0x02
-#define HCI_ACL_PKT_SIZE		(sizeof(hci_acldata_hdr_t) + 0xffff)
-
-/* SCO data packet header */
-typedef struct {
-	uint8_t		type;	    /* MUST be 0x03 */
-	uint16_t	con_handle; /* connection handle + reserved bits */
-	uint8_t		length;     /* payload length in bytes */
-} __attribute__ ((__packed__)) hci_scodata_hdr_t;
-
-#define HCI_SCO_DATA_PKT		0x03
-#define HCI_SCO_PKT_SIZE		(sizeof(hci_scodata_hdr_t) + 0xff)
-
-/* HCI event packet header */
-typedef struct {
-	uint8_t		type;	/* MUST be 0x04 */
-	uint8_t		event;  /* event */
-	uint8_t		length; /* parameter(s) length in bytes */
-} __attribute__ ((__packed__)) hci_event_hdr_t;
-
-#define HCI_EVENT_PKT			0x04
-#define HCI_EVENT_PKT_SIZE		(sizeof(hci_event_hdr_t) + 0xff)
-
-/* HCI status return parameter */
-typedef struct {
-	uint8_t		status; /* 0x00 - success */
-} __attribute__ ((__packed__)) hci_status_rp;
-
-/**************************************************************************
- **************************************************************************
- ** OGF 0x01	Link control commands and return parameters
- **************************************************************************
- **************************************************************************/
-
-#define HCI_OGF_LINK_CONTROL			0x01
-
-#define HCI_OCF_INQUIRY					0x0001
-#define HCI_CMD_INQUIRY					0x0401
-typedef struct {
-	uint8_t		lap[HCI_LAP_SIZE]; /* LAP */
-	uint8_t		inquiry_length;    /* (N x 1.28) sec */
-	uint8_t		num_responses;     /* Max. # of responses */
-} __attribute__ ((__packed__)) hci_inquiry_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_INQUIRY_CANCEL				0x0002
-#define HCI_CMD_INQUIRY_CANCEL				0x0402
-/* No command parameter(s) */
-typedef hci_status_rp	hci_inquiry_cancel_rp;
-
-#define HCI_OCF_PERIODIC_INQUIRY			0x0003
-#define HCI_CMD_PERIODIC_INQUIRY			0x0403
-typedef struct {
-	uint16_t	max_period_length; /* Max. and min. amount of time */
-	uint16_t	min_period_length; /* between consecutive inquiries */
-	uint8_t		lap[HCI_LAP_SIZE]; /* LAP */
-	uint8_t		inquiry_length;    /* (inquiry_length * 1.28) sec */
-	uint8_t		num_responses;     /* Max. # of responses */
-} __attribute__ ((__packed__)) hci_periodic_inquiry_cp;
-
-typedef hci_status_rp	hci_periodic_inquiry_rp;
-
-#define HCI_OCF_EXIT_PERIODIC_INQUIRY			0x0004
-#define HCI_CMD_EXIT_PERIODIC_INQUIRY			0x0404
-/* No command parameter(s) */
-typedef hci_status_rp	hci_exit_periodic_inquiry_rp;
-
-#define HCI_OCF_CREATE_CON				0x0005
-#define HCI_CMD_CREATE_CON				0x0405
-typedef struct {
-	bdaddr_t	bdaddr;             /* destination address */
-	uint16_t	pkt_type;           /* packet type */
-	uint8_t		page_scan_rep_mode; /* page scan repetition mode */
-	uint8_t		page_scan_mode;     /* reserved - set to 0x00 */
-	uint16_t	clock_offset;       /* clock offset */
-	uint8_t		accept_role_switch; /* accept role switch? 0x00 == No */
-} __attribute__ ((__packed__)) hci_create_con_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_DISCONNECT				0x0006
-#define HCI_CMD_DISCONNECT				0x0406
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-	uint8_t		reason;     /* reason to disconnect */
-} __attribute__ ((__packed__)) hci_discon_cp;
-/* No return parameter(s) */
-
-/* Add SCO Connection is deprecated */
-#define HCI_OCF_ADD_SCO_CON				0x0007
-#define HCI_CMD_ADD_SCO_CON				0x0407
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-	uint16_t	pkt_type;   /* packet type */
-} __attribute__ ((__packed__)) hci_add_sco_con_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_CREATE_CON_CANCEL			0x0008
-#define HCI_CMD_CREATE_CON_CANCEL			0x0408
-typedef struct {
-	bdaddr_t	bdaddr;		/* destination address */
-} __attribute__ ((__packed__)) hci_create_con_cancel_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* destination address */
-} __attribute__ ((__packed__)) hci_create_con_cancel_rp;
-
-#define HCI_OCF_ACCEPT_CON				0x0009
-#define HCI_CMD_ACCEPT_CON				0x0409
-typedef struct {
-	bdaddr_t	bdaddr; /* address of unit to be connected */
-	uint8_t		role;   /* connection role */
-} __attribute__ ((__packed__)) hci_accept_con_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_REJECT_CON				0x000a
-#define HCI_CMD_REJECT_CON				0x040A
-typedef struct {
-	bdaddr_t	bdaddr; /* remote address */
-	uint8_t		reason; /* reason to reject */
-} __attribute__ ((__packed__)) hci_reject_con_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_LINK_KEY_REP				0x000b
-#define HCI_CMD_LINK_KEY_REP				0x040B
-typedef struct {
-	bdaddr_t	bdaddr;            /* remote address */
-	uint8_t		key[HCI_KEY_SIZE]; /* key */
-} __attribute__ ((__packed__)) hci_link_key_rep_cp;
-
-typedef struct {
-	uint8_t		status; /* 0x00 - success */
-	bdaddr_t	bdaddr; /* unit address */
-} __attribute__ ((__packed__)) hci_link_key_rep_rp;
-
-#define HCI_OCF_LINK_KEY_NEG_REP			0x000c
-#define HCI_CMD_LINK_KEY_NEG_REP			0x040C
-typedef struct {
-	bdaddr_t	bdaddr; /* remote address */
-} __attribute__ ((__packed__)) hci_link_key_neg_rep_cp;
-
-typedef struct {
-	uint8_t		status; /* 0x00 - success */
-	bdaddr_t	bdaddr; /* unit address */
-} __attribute__ ((__packed__)) hci_link_key_neg_rep_rp;
-
-#define HCI_OCF_PIN_CODE_REP				0x000d
-#define HCI_CMD_PIN_CODE_REP				0x040D
-typedef struct {
-	bdaddr_t	bdaddr;               /* remote address */
-	uint8_t		pin_size;             /* pin code length (in bytes) */
-	uint8_t		pin[HCI_PIN_SIZE];    /* pin code */
-} __attribute__ ((__packed__)) hci_pin_code_rep_cp;
-
-typedef struct {
-	uint8_t		status; /* 0x00 - success */
-	bdaddr_t	bdaddr; /* unit address */
-} __attribute__ ((__packed__)) hci_pin_code_rep_rp;
-
-#define HCI_OCF_PIN_CODE_NEG_REP			0x000e
-#define HCI_CMD_PIN_CODE_NEG_REP			0x040E
-typedef struct {
-	bdaddr_t	bdaddr; /* remote address */
-} __attribute__ ((__packed__)) hci_pin_code_neg_rep_cp;
-
-typedef struct {
-	uint8_t		status; /* 0x00 - success */
-	bdaddr_t	bdaddr; /* unit address */
-} __attribute__ ((__packed__)) hci_pin_code_neg_rep_rp;
-
-#define HCI_OCF_CHANGE_CON_PACKET_TYPE			0x000f
-#define HCI_CMD_CHANGE_CON_PACKET_TYPE			0x040F
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-	uint16_t	pkt_type;   /* packet type */
-} __attribute__ ((__packed__)) hci_change_con_pkt_type_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_AUTH_REQ				0x0011
-#define HCI_CMD_AUTH_REQ				0x0411
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_auth_req_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_SET_CON_ENCRYPTION			0x0013
-#define HCI_CMD_SET_CON_ENCRYPTION			0x0413
-typedef struct {
-	uint16_t	con_handle;        /* connection handle */
-	uint8_t		encryption_enable; /* 0x00 - disable, 0x01 - enable */
-} __attribute__ ((__packed__)) hci_set_con_encryption_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_CHANGE_CON_LINK_KEY			0x0015
-#define HCI_CMD_CHANGE_CON_LINK_KEY			0x0415
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_change_con_link_key_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_MASTER_LINK_KEY				0x0017
-#define HCI_CMD_MASTER_LINK_KEY				0x0417
-typedef struct {
-	uint8_t		key_flag; /* key flag */
-} __attribute__ ((__packed__)) hci_master_link_key_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_REMOTE_NAME_REQ				0x0019
-#define HCI_CMD_REMOTE_NAME_REQ				0x0419
-typedef struct {
-	bdaddr_t	bdaddr;             /* remote address */
-	uint8_t		page_scan_rep_mode; /* page scan repetition mode */
-	uint8_t		page_scan_mode;     /* page scan mode */
-	uint16_t	clock_offset;       /* clock offset */
-} __attribute__ ((__packed__)) hci_remote_name_req_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_REMOTE_NAME_REQ_CANCEL			0x001a
-#define HCI_CMD_REMOTE_NAME_REQ_CANCEL			0x041A
-typedef struct {
-	bdaddr_t	bdaddr;             /* remote address */
-} __attribute__ ((__packed__)) hci_remote_name_req_cancel_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;         /* remote address */
-} __attribute__ ((__packed__)) hci_remote_name_req_cancel_rp;
-
-#define HCI_OCF_READ_REMOTE_FEATURES			0x001b
-#define HCI_CMD_READ_REMOTE_FEATURES			0x041B
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_remote_features_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_READ_REMOTE_EXTENDED_FEATURES		0x001c
-#define HCI_CMD_READ_REMOTE_EXTENDED_FEATURES		0x041C
-typedef struct {
-	uint16_t	con_handle;	/* connection handle */
-	uint8_t		page;		/* page number */
-} __attribute__ ((__packed__)) hci_read_remote_extended_features_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_READ_REMOTE_VER_INFO			0x001d
-#define HCI_CMD_READ_REMOTE_VER_INFO			0x041D
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_remote_ver_info_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_READ_CLOCK_OFFSET			0x001f
-#define HCI_CMD_READ_CLOCK_OFFSET			0x041F
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_clock_offset_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_READ_LMP_HANDLE				0x0020
-#define HCI_CMD_READ_LMP_HANDLE				0x0420
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_lmp_handle_cp;
-
-typedef struct {
-	uint8_t		status;	    /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint8_t		lmp_handle; /* LMP handle */
-	uint32_t	reserved;   /* reserved */
-} __attribute__ ((__packed__)) hci_read_lmp_handle_rp;
-
-#define HCI_OCF_SETUP_SCO_CON				0x0028
-#define HCI_CMD_SETUP_SCO_CON				0x0428
-typedef struct {
-	uint16_t	con_handle;	/* connection handle */
-	uint32_t	tx_bandwidth;	/* transmit bandwidth */
-	uint32_t	rx_bandwidth;	/* receive bandwidth */
-	uint16_t	latency;	/* maximum latency */
-	uint16_t	voice;		/* voice setting */
-	uint8_t		rt_effort;	/* retransmission effort */
-	uint16_t	pkt_type;	/* packet types */
-} __attribute__ ((__packed__)) hci_setup_sco_con_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_ACCEPT_SCO_CON_REQ			0x0029
-#define HCI_CMD_ACCEPT_SCO_CON_REQ			0x0429
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-	uint32_t	tx_bandwidth;	/* transmit bandwidth */
-	uint32_t	rx_bandwidth;	/* receive bandwidth */
-	uint16_t	latency;	/* maximum latency */
-	uint16_t	content;	/* voice setting */
-	uint8_t		rt_effort;	/* retransmission effort */
-	uint16_t	pkt_type;	/* packet types */
-} __attribute__ ((__packed__)) hci_accept_sco_con_req_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_REJECT_SCO_CON_REQ			0x002a
-#define HCI_CMD_REJECT_SCO_CON_REQ			0x042a
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-	uint8_t		reason;		/* reject error code */
-} __attribute__ ((__packed__)) hci_reject_sco_con_req_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_IO_CAPABILITY_REP			0x002b
-#define HCI_CMD_IO_CAPABILITY_REP			0x042a
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-	uint8_t		io_cap;		/* IO capability */
-	uint8_t		oob_data;	/* OOB data present */
-	uint8_t		auth_req;	/* auth requirements */
-} __attribute__ ((__packed__)) hci_io_capability_rep_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_io_capability_rep_rp;
-
-#define HCI_OCF_USER_CONFIRM_REP			0x002c
-#define HCI_CMD_USER_CONFIRM_REP			0x042c
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_user_confirm_rep_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_user_confirm_rep_rp;
-
-#define HCI_OCF_USER_CONFIRM_NEG_REP			0x002d
-#define HCI_CMD_USER_CONFIRM_NEG_REP			0x042d
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_user_confirm_neg_rep_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_user_confirm_neg_rep_rp;
-
-#define HCI_OCF_USER_PASSKEY_REP			0x002e
-#define HCI_CMD_USER_PASSKEY_REP			0x042e
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-	uint32_t	value;		/* 000000 - 999999 */
-} __attribute__ ((__packed__)) hci_user_passkey_rep_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_user_passkey_rep_rp;
-
-#define HCI_OCF_USER_PASSKEY_NEG_REP			0x002f
-#define HCI_CMD_USER_PASSKEY_NEG_REP			0x042f
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_user_passkey_neg_rep_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_user_passkey_neg_rep_rp;
-
-#define HCI_OCF_OOB_DATA_REP				0x0030
-#define HCI_CMD_OOB_DATA_REP				0x0430
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-	uint8_t		c[16];		/* pairing hash */
-	uint8_t		r[16];		/* pairing randomizer */
-} __attribute__ ((__packed__)) hci_user_oob_data_rep_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_user_oob_data_rep_rp;
-
-#define HCI_OCF_OOB_DATA_NEG_REP			0x0033
-#define HCI_CMD_OOB_DATA_NEG_REP			0x0433
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_user_oob_data_neg_rep_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_user_oob_data_neg_rep_rp;
-
-#define HCI_OCF_IO_CAPABILITY_NEG_REP			0x0034
-#define HCI_CMD_IO_CAPABILITY_NEG_REP			0x0434
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-	uint8_t		reason;		/* error code */
-} __attribute__ ((__packed__)) hci_io_capability_neg_rep_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_io_capability_neg_rep_rp;
-
-/**************************************************************************
- **************************************************************************
- ** OGF 0x02	Link policy commands and return parameters
- **************************************************************************
- **************************************************************************/
-
-#define HCI_OGF_LINK_POLICY			0x02
-
-#define HCI_OCF_HOLD_MODE				0x0001
-#define HCI_CMD_HOLD_MODE				0x0801
-typedef struct {
-	uint16_t	con_handle;   /* connection handle */
-	uint16_t	max_interval; /* (max_interval * 0.625) msec */
-	uint16_t	min_interval; /* (max_interval * 0.625) msec */
-} __attribute__ ((__packed__)) hci_hold_mode_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_SNIFF_MODE				0x0003
-#define HCI_CMD_SNIFF_MODE				0x0803
-typedef struct {
-	uint16_t	con_handle;   /* connection handle */
-	uint16_t	max_interval; /* (max_interval * 0.625) msec */
-	uint16_t	min_interval; /* (max_interval * 0.625) msec */
-	uint16_t	attempt;      /* (2 * attempt - 1) * 0.625 msec */
-	uint16_t	timeout;      /* (2 * attempt - 1) * 0.625 msec */
-} __attribute__ ((__packed__)) hci_sniff_mode_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_EXIT_SNIFF_MODE				0x0004
-#define HCI_CMD_EXIT_SNIFF_MODE				0x0804
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_exit_sniff_mode_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_PARK_MODE				0x0005
-#define HCI_CMD_PARK_MODE				0x0805
-typedef struct {
-	uint16_t	con_handle;   /* connection handle */
-	uint16_t	max_interval; /* (max_interval * 0.625) msec */
-	uint16_t	min_interval; /* (max_interval * 0.625) msec */
-} __attribute__ ((__packed__)) hci_park_mode_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_EXIT_PARK_MODE				0x0006
-#define HCI_CMD_EXIT_PARK_MODE				0x0806
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_exit_park_mode_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_QOS_SETUP				0x0007
-#define HCI_CMD_QOS_SETUP				0x0807
-typedef struct {
-	uint16_t	con_handle;      /* connection handle */
-	uint8_t		flags;           /* reserved for future use */
-	uint8_t		service_type;    /* service type */
-	uint32_t	token_rate;      /* bytes per second */
-	uint32_t	peak_bandwidth;  /* bytes per second */
-	uint32_t	latency;         /* microseconds */
-	uint32_t	delay_variation; /* microseconds */
-} __attribute__ ((__packed__)) hci_qos_setup_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_ROLE_DISCOVERY				0x0009
-#define HCI_CMD_ROLE_DISCOVERY				0x0809
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_role_discovery_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint8_t		role;       /* role for the connection handle */
-} __attribute__ ((__packed__)) hci_role_discovery_rp;
-
-#define HCI_OCF_SWITCH_ROLE				0x000b
-#define HCI_CMD_SWITCH_ROLE				0x080B
-typedef struct {
-	bdaddr_t	bdaddr; /* remote address */
-	uint8_t		role;   /* new local role */
-} __attribute__ ((__packed__)) hci_switch_role_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_READ_LINK_POLICY_SETTINGS		0x000c
-#define HCI_CMD_READ_LINK_POLICY_SETTINGS		0x080C
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_link_policy_settings_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint16_t	settings;   /* link policy settings */
-} __attribute__ ((__packed__)) hci_read_link_policy_settings_rp;
-
-#define HCI_OCF_WRITE_LINK_POLICY_SETTINGS		0x000d
-#define HCI_CMD_WRITE_LINK_POLICY_SETTINGS		0x080D
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-	uint16_t	settings;   /* link policy settings */
-} __attribute__ ((__packed__)) hci_write_link_policy_settings_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_write_link_policy_settings_rp;
-
-#define HCI_OCF_READ_DEFAULT_LINK_POLICY_SETTINGS	0x000e
-#define HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS	0x080E
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	settings;   /* link policy settings */
-} __attribute__ ((__packed__)) hci_read_default_link_policy_settings_rp;
-
-#define HCI_OCF_WRITE_DEFAULT_LINK_POLICY_SETTINGS	0x000f
-#define HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS	0x080F
-typedef struct {
-	uint16_t	settings;   /* link policy settings */
-} __attribute__ ((__packed__)) hci_write_default_link_policy_settings_cp;
-
-typedef hci_status_rp	hci_write_default_link_policy_settings_rp;
-
-#define HCI_OCF_FLOW_SPECIFICATION			0x0010
-#define HCI_CMD_FLOW_SPECIFICATION			0x0810
-typedef struct {
-	uint16_t	con_handle;	/* connection handle */
-	uint8_t		flags;		/* reserved */
-	uint8_t		flow_direction;
-	uint8_t		service_type;
-	uint32_t	token_rate;
-	uint32_t	token_bucket;
-	uint32_t	peak_bandwidth;
-	uint32_t	latency;
-} __attribute__ ((__packed__)) hci_flow_specification_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_SNIFF_SUBRATING				0x0011
-#define HCI_CMD_SNIFF_SUBRATING				0x0810
-typedef struct {
-	uint16_t	con_handle;	/* connection handle */
-	uint16_t	max_latency;
-	uint16_t	max_timeout;	/* max remote timeout */
-	uint16_t	min_timeout;	/* min local timeout */
-} __attribute__ ((__packed__)) hci_sniff_subrating_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint16_t	con_handle;	/* connection handle */
-} __attribute__ ((__packed__)) hci_sniff_subrating_rp;
-
-/**************************************************************************
- **************************************************************************
- ** OGF 0x03	Host Controller and Baseband commands and return parameters
- **************************************************************************
- **************************************************************************/
-
-#define HCI_OGF_HC_BASEBAND			0x03
-
-#define HCI_OCF_SET_EVENT_MASK				0x0001
-#define HCI_CMD_SET_EVENT_MASK				0x0C01
-typedef struct {
-	uint8_t		event_mask[HCI_EVENT_MASK_SIZE]; /* event_mask */
-} __attribute__ ((__packed__)) hci_set_event_mask_cp;
-
-typedef hci_status_rp	hci_set_event_mask_rp;
-
-#define HCI_OCF_RESET					0x0003
-#define HCI_CMD_RESET					0x0C03
-/* No command parameter(s) */
-typedef hci_status_rp	hci_reset_rp;
-
-#define HCI_OCF_SET_EVENT_FILTER			0x0005
-#define HCI_CMD_SET_EVENT_FILTER			0x0C05
-typedef struct {
-	uint8_t		filter_type;           /* filter type */
-	uint8_t		filter_condition_type; /* filter condition type */
-/* variable size condition
-	uint8_t		condition[]; -- conditions */
-} __attribute__ ((__packed__)) hci_set_event_filter_cp;
-
-typedef hci_status_rp	hci_set_event_filter_rp;
-
-#define HCI_OCF_FLUSH					0x0008
-#define HCI_CMD_FLUSH					0x0C08
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_flush_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_flush_rp;
-
-#define HCI_OCF_READ_PIN_TYPE				0x0009
-#define HCI_CMD_READ_PIN_TYPE				0x0C09
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;   /* 0x00 - success */
-	uint8_t		pin_type; /* PIN type */
-} __attribute__ ((__packed__)) hci_read_pin_type_rp;
-
-#define HCI_OCF_WRITE_PIN_TYPE				0x000a
-#define HCI_CMD_WRITE_PIN_TYPE				0x0C0A
-typedef struct {
-	uint8_t		pin_type; /* PIN type */
-} __attribute__ ((__packed__)) hci_write_pin_type_cp;
-
-typedef hci_status_rp	hci_write_pin_type_rp;
-
-#define HCI_OCF_CREATE_NEW_UNIT_KEY			0x000b
-#define HCI_CMD_CREATE_NEW_UNIT_KEY			0x0C0B
-/* No command parameter(s) */
-typedef hci_status_rp	hci_create_new_unit_key_rp;
-
-#define HCI_OCF_READ_STORED_LINK_KEY			0x000d
-#define HCI_CMD_READ_STORED_LINK_KEY			0x0C0D
-typedef struct {
-	bdaddr_t	bdaddr;   /* address */
-	uint8_t		read_all; /* read all keys? 0x01 - yes */
-} __attribute__ ((__packed__)) hci_read_stored_link_key_cp;
-
-typedef struct {
-	uint8_t		status;        /* 0x00 - success */
-	uint16_t	max_num_keys;  /* Max. number of keys */
-	uint16_t	num_keys_read; /* Number of stored keys */
-} __attribute__ ((__packed__)) hci_read_stored_link_key_rp;
-
-#define HCI_OCF_WRITE_STORED_LINK_KEY			0x0011
-#define HCI_CMD_WRITE_STORED_LINK_KEY			0x0C11
-typedef struct {
-	uint8_t		num_keys_write; /* # of keys to write */
-/* these are repeated "num_keys_write" times
-	bdaddr_t	bdaddr;             --- remote address(es)
-	uint8_t		key[HCI_KEY_SIZE];  --- key(s) */
-} __attribute__ ((__packed__)) hci_write_stored_link_key_cp;
-
-typedef struct {
-	uint8_t		status;           /* 0x00 - success */
-	uint8_t		num_keys_written; /* # of keys successfully written */
-} __attribute__ ((__packed__)) hci_write_stored_link_key_rp;
-
-#define HCI_OCF_DELETE_STORED_LINK_KEY			0x0012
-#define HCI_CMD_DELETE_STORED_LINK_KEY			0x0C12
-typedef struct {
-	bdaddr_t	bdaddr;     /* address */
-	uint8_t		delete_all; /* delete all keys? 0x01 - yes */
-} __attribute__ ((__packed__)) hci_delete_stored_link_key_cp;
-
-typedef struct {
-	uint8_t		status;           /* 0x00 - success */
-	uint16_t	num_keys_deleted; /* Number of keys deleted */
-} __attribute__ ((__packed__)) hci_delete_stored_link_key_rp;
-
-#define HCI_OCF_WRITE_LOCAL_NAME			0x0013
-#define HCI_CMD_WRITE_LOCAL_NAME			0x0C13
-typedef struct {
-	char		name[HCI_UNIT_NAME_SIZE]; /* new unit name */
-} __attribute__ ((__packed__)) hci_write_local_name_cp;
-
-typedef hci_status_rp	hci_write_local_name_rp;
-
-#define HCI_OCF_READ_LOCAL_NAME				0x0014
-#define HCI_CMD_READ_LOCAL_NAME				0x0C14
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;                   /* 0x00 - success */
-	char		name[HCI_UNIT_NAME_SIZE]; /* unit name */
-} __attribute__ ((__packed__)) hci_read_local_name_rp;
-
-#define HCI_OCF_READ_CON_ACCEPT_TIMEOUT			0x0015
-#define HCI_CMD_READ_CON_ACCEPT_TIMEOUT			0x0C15
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;  /* 0x00 - success */
-	uint16_t	timeout; /* (timeout * 0.625) msec */
-} __attribute__ ((__packed__)) hci_read_con_accept_timeout_rp;
-
-#define HCI_OCF_WRITE_CON_ACCEPT_TIMEOUT		0x0016
-#define HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT		0x0C16
-typedef struct {
-	uint16_t	timeout; /* (timeout * 0.625) msec */
-} __attribute__ ((__packed__)) hci_write_con_accept_timeout_cp;
-
-typedef hci_status_rp	hci_write_con_accept_timeout_rp;
-
-#define HCI_OCF_READ_PAGE_TIMEOUT			0x0017
-#define HCI_CMD_READ_PAGE_TIMEOUT			0x0C17
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;  /* 0x00 - success */
-	uint16_t	timeout; /* (timeout * 0.625) msec */
-} __attribute__ ((__packed__)) hci_read_page_timeout_rp;
-
-#define HCI_OCF_WRITE_PAGE_TIMEOUT			0x0018
-#define HCI_CMD_WRITE_PAGE_TIMEOUT			0x0C18
-typedef struct {
-	uint16_t	timeout; /* (timeout * 0.625) msec */
-} __attribute__ ((__packed__)) hci_write_page_timeout_cp;
-
-typedef hci_status_rp	hci_write_page_timeout_rp;
-
-#define HCI_OCF_READ_SCAN_ENABLE			0x0019
-#define HCI_CMD_READ_SCAN_ENABLE			0x0C19
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;      /* 0x00 - success */
-	uint8_t		scan_enable; /* Scan enable */
-} __attribute__ ((__packed__)) hci_read_scan_enable_rp;
-
-#define HCI_OCF_WRITE_SCAN_ENABLE			0x001a
-#define HCI_CMD_WRITE_SCAN_ENABLE			0x0C1A
-typedef struct {
-	uint8_t		scan_enable; /* Scan enable */
-} __attribute__ ((__packed__)) hci_write_scan_enable_cp;
-
-typedef hci_status_rp	hci_write_scan_enable_rp;
-
-#define HCI_OCF_READ_PAGE_SCAN_ACTIVITY			0x001b
-#define HCI_CMD_READ_PAGE_SCAN_ACTIVITY			0x0C1B
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;             /* 0x00 - success */
-	uint16_t	page_scan_interval; /* interval * 0.625 msec */
-	uint16_t	page_scan_window;   /* window * 0.625 msec */
-} __attribute__ ((__packed__)) hci_read_page_scan_activity_rp;
-
-#define HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY		0x001c
-#define HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY		0x0C1C
-typedef struct {
-	uint16_t	page_scan_interval; /* interval * 0.625 msec */
-	uint16_t	page_scan_window;   /* window * 0.625 msec */
-} __attribute__ ((__packed__)) hci_write_page_scan_activity_cp;
-
-typedef hci_status_rp	hci_write_page_scan_activity_rp;
-
-#define HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY		0x001d
-#define HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY		0x0C1D
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;                /* 0x00 - success */
-	uint16_t	inquiry_scan_interval; /* interval * 0.625 msec */
-	uint16_t	inquiry_scan_window;   /* window * 0.625 msec */
-} __attribute__ ((__packed__)) hci_read_inquiry_scan_activity_rp;
-
-#define HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY		0x001e
-#define HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY		0x0C1E
-typedef struct {
-	uint16_t	inquiry_scan_interval; /* interval * 0.625 msec */
-	uint16_t	inquiry_scan_window;   /* window * 0.625 msec */
-} __attribute__ ((__packed__)) hci_write_inquiry_scan_activity_cp;
-
-typedef hci_status_rp	hci_write_inquiry_scan_activity_rp;
-
-#define HCI_OCF_READ_AUTH_ENABLE			0x001f
-#define HCI_CMD_READ_AUTH_ENABLE			0x0C1F
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;      /* 0x00 - success */
-	uint8_t		auth_enable; /* 0x01 - enabled */
-} __attribute__ ((__packed__)) hci_read_auth_enable_rp;
-
-#define HCI_OCF_WRITE_AUTH_ENABLE			0x0020
-#define HCI_CMD_WRITE_AUTH_ENABLE			0x0C20
-typedef struct {
-	uint8_t		auth_enable; /* 0x01 - enabled */
-} __attribute__ ((__packed__)) hci_write_auth_enable_cp;
-
-typedef hci_status_rp	hci_write_auth_enable_rp;
-
-/* Read Encryption Mode is deprecated */
-#define HCI_OCF_READ_ENCRYPTION_MODE			0x0021
-#define HCI_CMD_READ_ENCRYPTION_MODE			0x0C21
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;          /* 0x00 - success */
-	uint8_t		encryption_mode; /* encryption mode */
-} __attribute__ ((__packed__)) hci_read_encryption_mode_rp;
-
-/* Write Encryption Mode is deprecated */
-#define HCI_OCF_WRITE_ENCRYPTION_MODE			0x0022
-#define HCI_CMD_WRITE_ENCRYPTION_MODE			0x0C22
-typedef struct {
-	uint8_t		encryption_mode; /* encryption mode */
-} __attribute__ ((__packed__)) hci_write_encryption_mode_cp;
-
-typedef hci_status_rp	hci_write_encryption_mode_rp;
-
-#define HCI_OCF_READ_UNIT_CLASS				0x0023
-#define HCI_CMD_READ_UNIT_CLASS				0x0C23
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;                 /* 0x00 - success */
-	uint8_t		uclass[HCI_CLASS_SIZE]; /* unit class */
-} __attribute__ ((__packed__)) hci_read_unit_class_rp;
-
-#define HCI_OCF_WRITE_UNIT_CLASS			0x0024
-#define HCI_CMD_WRITE_UNIT_CLASS			0x0C24
-typedef struct {
-	uint8_t		uclass[HCI_CLASS_SIZE]; /* unit class */
-} __attribute__ ((__packed__)) hci_write_unit_class_cp;
-
-typedef hci_status_rp	hci_write_unit_class_rp;
-
-#define HCI_OCF_READ_VOICE_SETTING			0x0025
-#define HCI_CMD_READ_VOICE_SETTING			0x0C25
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;   /* 0x00 - success */
-	uint16_t	settings; /* voice settings */
-} __attribute__ ((__packed__)) hci_read_voice_setting_rp;
-
-#define HCI_OCF_WRITE_VOICE_SETTING			0x0026
-#define HCI_CMD_WRITE_VOICE_SETTING			0x0C26
-typedef struct {
-	uint16_t	settings; /* voice settings */
-} __attribute__ ((__packed__)) hci_write_voice_setting_cp;
-
-typedef hci_status_rp	hci_write_voice_setting_rp;
-
-#define HCI_OCF_READ_AUTO_FLUSH_TIMEOUT			0x0027
-#define HCI_CMD_READ_AUTO_FLUSH_TIMEOUT			0x0C27
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_auto_flush_timeout_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint16_t	timeout;    /* 0x00 - no flush, timeout * 0.625 msec */
-} __attribute__ ((__packed__)) hci_read_auto_flush_timeout_rp;
-
-#define HCI_OCF_WRITE_AUTO_FLUSH_TIMEOUT		0x0028
-#define HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT		0x0C28
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-	uint16_t	timeout;    /* 0x00 - no flush, timeout * 0.625 msec */
-} __attribute__ ((__packed__)) hci_write_auto_flush_timeout_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_write_auto_flush_timeout_rp;
-
-#define HCI_OCF_READ_NUM_BROADCAST_RETRANS		0x0029
-#define HCI_CMD_READ_NUM_BROADCAST_RETRANS		0x0C29
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;  /* 0x00 - success */
-	uint8_t		counter; /* number of broadcast retransmissions */
-} __attribute__ ((__packed__)) hci_read_num_broadcast_retrans_rp;
-
-#define HCI_OCF_WRITE_NUM_BROADCAST_RETRANS		0x002a
-#define HCI_CMD_WRITE_NUM_BROADCAST_RETRANS		0x0C2A
-typedef struct {
-	uint8_t		counter; /* number of broadcast retransmissions */
-} __attribute__ ((__packed__)) hci_write_num_broadcast_retrans_cp;
-
-typedef hci_status_rp	hci_write_num_broadcast_retrans_rp;
-
-#define HCI_OCF_READ_HOLD_MODE_ACTIVITY			0x002b
-#define HCI_CMD_READ_HOLD_MODE_ACTIVITY			0x0C2B
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;             /* 0x00 - success */
-	uint8_t		hold_mode_activity; /* Hold mode activities */
-} __attribute__ ((__packed__)) hci_read_hold_mode_activity_rp;
-
-#define HCI_OCF_WRITE_HOLD_MODE_ACTIVITY		0x002c
-#define HCI_CMD_WRITE_HOLD_MODE_ACTIVITY		0x0C2C
-typedef struct {
-	uint8_t		hold_mode_activity; /* Hold mode activities */
-} __attribute__ ((__packed__)) hci_write_hold_mode_activity_cp;
-
-typedef hci_status_rp	hci_write_hold_mode_activity_rp;
-
-#define HCI_OCF_READ_XMIT_LEVEL				0x002d
-#define HCI_CMD_READ_XMIT_LEVEL				0x0C2D
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-	uint8_t		type;       /* Xmit level type */
-} __attribute__ ((__packed__)) hci_read_xmit_level_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	char		level;      /* -30 <= level <= 30 dBm */
-} __attribute__ ((__packed__)) hci_read_xmit_level_rp;
-
-#define HCI_OCF_READ_SCO_FLOW_CONTROL			0x002e
-#define HCI_CMD_READ_SCO_FLOW_CONTROL			0x0C2E
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;       /* 0x00 - success */
-	uint8_t		flow_control; /* 0x00 - disabled */
-} __attribute__ ((__packed__)) hci_read_sco_flow_control_rp;
-
-#define HCI_OCF_WRITE_SCO_FLOW_CONTROL			0x002f
-#define HCI_CMD_WRITE_SCO_FLOW_CONTROL			0x0C2F
-typedef struct {
-	uint8_t		flow_control; /* 0x00 - disabled */
-} __attribute__ ((__packed__)) hci_write_sco_flow_control_cp;
-
-typedef hci_status_rp	hci_write_sco_flow_control_rp;
-
-#define HCI_OCF_HC2H_FLOW_CONTROL			0x0031
-#define HCI_CMD_HC2H_FLOW_CONTROL			0x0C31
-typedef struct {
-	uint8_t		hc2h_flow; /* Host Controller to Host flow control */
-} __attribute__ ((__packed__)) hci_hc2h_flow_control_cp;
-
-typedef hci_status_rp	hci_h2hc_flow_control_rp;
-
-#define HCI_OCF_HOST_BUFFER_SIZE			0x0033
-#define HCI_CMD_HOST_BUFFER_SIZE			0x0C33
-typedef struct {
-	uint16_t	max_acl_size; /* Max. size of ACL packet (bytes) */
-	uint8_t		max_sco_size; /* Max. size of SCO packet (bytes) */
-	uint16_t	num_acl_pkts;  /* Max. number of ACL packets */
-	uint16_t	num_sco_pkts;  /* Max. number of SCO packets */
-} __attribute__ ((__packed__)) hci_host_buffer_size_cp;
-
-typedef hci_status_rp	hci_host_buffer_size_rp;
-
-#define HCI_OCF_HOST_NUM_COMPL_PKTS			0x0035
-#define HCI_CMD_HOST_NUM_COMPL_PKTS			0x0C35
-typedef struct {
-	uint8_t		nu_con_handles; /* # of connection handles */
-/* these are repeated "num_con_handles" times
-	uint16_t	con_handle;    --- connection handle(s)
-	uint16_t	compl_pkts;    --- # of completed packets */
-} __attribute__ ((__packed__)) hci_host_num_compl_pkts_cp;
-/* No return parameter(s) */
-
-#define HCI_OCF_READ_LINK_SUPERVISION_TIMEOUT		0x0036
-#define HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT		0x0C36
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_link_supervision_timeout_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint16_t	timeout;    /* Link supervision timeout * 0.625 msec */
-} __attribute__ ((__packed__)) hci_read_link_supervision_timeout_rp;
-
-#define HCI_OCF_WRITE_LINK_SUPERVISION_TIMEOUT		0x0037
-#define HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT		0x0C37
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-	uint16_t	timeout;    /* Link supervision timeout * 0.625 msec */
-} __attribute__ ((__packed__)) hci_write_link_supervision_timeout_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_write_link_supervision_timeout_rp;
-
-#define HCI_OCF_READ_NUM_SUPPORTED_IAC			0x0038
-#define HCI_CMD_READ_NUM_SUPPORTED_IAC			0x0C38
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;  /* 0x00 - success */
-	uint8_t		num_iac; /* # of supported IAC during scan */
-} __attribute__ ((__packed__)) hci_read_num_supported_iac_rp;
-
-#define HCI_OCF_READ_IAC_LAP				0x0039
-#define HCI_CMD_READ_IAC_LAP				0x0C39
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;  /* 0x00 - success */
-	uint8_t		num_iac; /* # of IAC */
-/* these are repeated "num_iac" times
-	uint8_t		laps[HCI_LAP_SIZE]; --- LAPs */
-} __attribute__ ((__packed__)) hci_read_iac_lap_rp;
-
-#define HCI_OCF_WRITE_IAC_LAP				0x003a
-#define HCI_CMD_WRITE_IAC_LAP				0x0C3A
-typedef struct {
-	uint8_t		num_iac; /* # of IAC */
-/* these are repeated "num_iac" times
-	uint8_t		laps[HCI_LAP_SIZE]; --- LAPs */
-} __attribute__ ((__packed__)) hci_write_iac_lap_cp;
-
-typedef hci_status_rp	hci_write_iac_lap_rp;
-
-/* Read Page Scan Period Mode is deprecated */
-#define HCI_OCF_READ_PAGE_SCAN_PERIOD			0x003b
-#define HCI_CMD_READ_PAGE_SCAN_PERIOD			0x0C3B
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;                /* 0x00 - success */
-	uint8_t		page_scan_period_mode; /* Page scan period mode */
-} __attribute__ ((__packed__)) hci_read_page_scan_period_rp;
-
-/* Write Page Scan Period Mode is deprecated */
-#define HCI_OCF_WRITE_PAGE_SCAN_PERIOD			0x003c
-#define HCI_CMD_WRITE_PAGE_SCAN_PERIOD			0x0C3C
-typedef struct {
-	uint8_t		page_scan_period_mode; /* Page scan period mode */
-} __attribute__ ((__packed__)) hci_write_page_scan_period_cp;
-
-typedef hci_status_rp	hci_write_page_scan_period_rp;
-
-/* Read Page Scan Mode is deprecated */
-#define HCI_OCF_READ_PAGE_SCAN				0x003d
-#define HCI_CMD_READ_PAGE_SCAN				0x0C3D
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;         /* 0x00 - success */
-	uint8_t		page_scan_mode; /* Page scan mode */
-} __attribute__ ((__packed__)) hci_read_page_scan_rp;
-
-/* Write Page Scan Mode is deprecated */
-#define HCI_OCF_WRITE_PAGE_SCAN				0x003e
-#define HCI_CMD_WRITE_PAGE_SCAN				0x0C3E
-typedef struct {
-	uint8_t		page_scan_mode; /* Page scan mode */
-} __attribute__ ((__packed__)) hci_write_page_scan_cp;
-
-typedef hci_status_rp	hci_write_page_scan_rp;
-
-#define HCI_OCF_SET_AFH_CLASSIFICATION			0x003f
-#define HCI_CMD_SET_AFH_CLASSIFICATION			0x0C3F
-typedef struct {
-	uint8_t		classification[10];
-} __attribute__ ((__packed__)) hci_set_afh_classification_cp;
-
-typedef hci_status_rp	hci_set_afh_classification_rp;
-
-#define HCI_OCF_READ_INQUIRY_SCAN_TYPE			0x0042
-#define HCI_CMD_READ_INQUIRY_SCAN_TYPE			0x0C42
-/* No command parameter(s) */
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint8_t		type;		/* inquiry scan type */
-} __attribute__ ((__packed__)) hci_read_inquiry_scan_type_rp;
-
-#define HCI_OCF_WRITE_INQUIRY_SCAN_TYPE			0x0043
-#define HCI_CMD_WRITE_INQUIRY_SCAN_TYPE			0x0C43
-typedef struct {
-	uint8_t		type;		/* inquiry scan type */
-} __attribute__ ((__packed__)) hci_write_inquiry_scan_type_cp;
-
-typedef hci_status_rp	hci_write_inquiry_scan_type_rp;
-
-#define HCI_OCF_READ_INQUIRY_MODE			0x0044
-#define HCI_CMD_READ_INQUIRY_MODE			0x0C44
-/* No command parameter(s) */
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint8_t		mode;		/* inquiry mode */
-} __attribute__ ((__packed__)) hci_read_inquiry_mode_rp;
-
-#define HCI_OCF_WRITE_INQUIRY_MODE			0x0045
-#define HCI_CMD_WRITE_INQUIRY_MODE			0x0C45
-typedef struct {
-	uint8_t		mode;		/* inquiry mode */
-} __attribute__ ((__packed__)) hci_write_inquiry_mode_cp;
-
-typedef hci_status_rp	hci_write_inquiry_mode_rp;
-
-#define HCI_OCF_READ_PAGE_SCAN_TYPE			0x0046
-#define HCI_CMD_READ_PAGE_SCAN_TYPE			0x0C46
-/* No command parameter(s) */
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint8_t		type;		/* page scan type */
-} __attribute__ ((__packed__)) hci_read_page_scan_type_rp;
-
-#define HCI_OCF_WRITE_PAGE_SCAN_TYPE			0x0047
-#define HCI_CMD_WRITE_PAGE_SCAN_TYPE			0x0C47
-typedef struct {
-	uint8_t		type;		/* page scan type */
-} __attribute__ ((__packed__)) hci_write_page_scan_type_cp;
-
-typedef hci_status_rp	hci_write_page_scan_type_rp;
-
-#define HCI_OCF_READ_AFH_ASSESSMENT			0x0048
-#define HCI_CMD_READ_AFH_ASSESSMENT			0x0C48
-/* No command parameter(s) */
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint8_t		mode;		/* assessment mode */
-} __attribute__ ((__packed__)) hci_read_afh_assessment_rp;
-
-#define HCI_OCF_WRITE_AFH_ASSESSMENT			0x0049
-#define HCI_CMD_WRITE_AFH_ASSESSMENT			0x0C49
-typedef struct {
-	uint8_t		mode;		/* assessment mode */
-} __attribute__ ((__packed__)) hci_write_afh_assessment_cp;
-
-typedef hci_status_rp	hci_write_afh_assessment_rp;
-
-#define HCI_OCF_READ_EXTENDED_INQUIRY_RSP		0x0051
-#define HCI_CMD_READ_EXTENDED_INQUIRY_RSP		0x0C51
-/* No command parameter(s) */
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint8_t		fec_required;
-	uint8_t		response[240];
-} __attribute__ ((__packed__)) hci_read_extended_inquiry_rsp_rp;
-
-#define HCI_OCF_WRITE_EXTENDED_INQUIRY_RSP		0x0052
-#define HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP		0x0C52
-typedef struct {
-	uint8_t		fec_required;
-	uint8_t		response[240];
-} __attribute__ ((__packed__)) hci_write_extended_inquiry_rsp_cp;
-
-typedef hci_status_rp	hci_write_extended_inquiry_rsp_rp;
-
-#define HCI_OCF_REFRESH_ENCRYPTION_KEY			0x0053
-#define HCI_CMD_REFRESH_ENCRYPTION_KEY			0x0C53
-typedef struct {
-	uint16_t	con_handle;	/* connection handle */
-} __attribute__ ((__packed__)) hci_refresh_encryption_key_cp;
-
-typedef hci_status_rp	hci_refresh_encryption_key_rp;
-
-#define HCI_OCF_READ_SIMPLE_PAIRING_MODE		0x0055
-#define HCI_CMD_READ_SIMPLE_PAIRING_MODE		0x0C55
-/* No command parameter(s) */
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint8_t		mode;		/* simple pairing mode */
-} __attribute__ ((__packed__)) hci_read_simple_pairing_mode_rp;
-
-#define HCI_OCF_WRITE_SIMPLE_PAIRING_MODE		0x0056
-#define HCI_CMD_WRITE_SIMPLE_PAIRING_MODE		0x0C56
-typedef struct {
-	uint8_t		mode;		/* simple pairing mode */
-} __attribute__ ((__packed__)) hci_write_simple_pairing_mode_cp;
-
-typedef hci_status_rp	hci_write_simple_pairing_mode_rp;
-
-#define HCI_OCF_READ_LOCAL_OOB_DATA			0x0057
-#define HCI_CMD_READ_LOCAL_OOB_DATA			0x0C57
-/* No command parameter(s) */
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint8_t		c[16];		/* pairing hash */
-	uint8_t		r[16];		/* pairing randomizer */
-} __attribute__ ((__packed__)) hci_read_local_oob_data_rp;
-
-#define HCI_OCF_READ_INQUIRY_RSP_XMIT_POWER		0x0058
-#define HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER		0x0C58
-/* No command parameter(s) */
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	int8_t		power;		/* TX power */
-} __attribute__ ((__packed__)) hci_read_inquiry_rsp_xmit_power_rp;
-
-#define HCI_OCF_WRITE_INQUIRY_RSP_XMIT_POWER		0x0059
-#define HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER		0x0C59
-typedef struct {
-	int8_t		power;		/* TX power */
-} __attribute__ ((__packed__)) hci_write_inquiry_rsp_xmit_power_cp;
-
-typedef hci_status_rp	hci_write_inquiry_rsp_xmit_power_rp;
-
-#define HCI_OCF_READ_DEFAULT_ERRDATA_REPORTING		0x005A
-#define HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING		0x0C5A
-/* No command parameter(s) */
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint8_t		reporting;	/* erroneous data reporting */
-} __attribute__ ((__packed__)) hci_read_default_errdata_reporting_rp;
-
-#define HCI_OCF_WRITE_DEFAULT_ERRDATA_REPORTING		0x005B
-#define HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING		0x0C5B
-typedef struct {
-	uint8_t		reporting;	/* erroneous data reporting */
-} __attribute__ ((__packed__)) hci_write_default_errdata_reporting_cp;
-
-typedef hci_status_rp	hci_write_default_errdata_reporting_rp;
-
-#define HCI_OCF_ENHANCED_FLUSH				0x005F
-#define HCI_CMD_ENHANCED_FLUSH				0x0C5F
-typedef struct {
-	uint16_t	con_handle;	/* connection handle */
-	uint8_t		packet_type;
-} __attribute__ ((__packed__)) hci_enhanced_flush_cp;
-
-/* No response parameter(s) */
-
-#define HCI_OCF_SEND_KEYPRESS_NOTIFICATION		0x0060
-#define HCI_CMD_SEND_KEYPRESS_NOTIFICATION		0x0C60
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote address */
-	uint8_t		type;		/* notification type */
-} __attribute__ ((__packed__)) hci_send_keypress_notification_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* remote address */
-} __attribute__ ((__packed__)) hci_send_keypress_notification_rp;
-
-/**************************************************************************
- **************************************************************************
- ** OGF 0x04	Informational commands and return parameters
- **************************************************************************
- **************************************************************************/
-
-#define HCI_OGF_INFO				0x04
-
-#define HCI_OCF_READ_LOCAL_VER				0x0001
-#define HCI_CMD_READ_LOCAL_VER				0x1001
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;         /* 0x00 - success */
-	uint8_t		hci_version;    /* HCI version */
-	uint16_t	hci_revision;   /* HCI revision */
-	uint8_t		lmp_version;    /* LMP version */
-	uint16_t	manufacturer;   /* Hardware manufacturer name */
-	uint16_t	lmp_subversion; /* LMP sub-version */
-} __attribute__ ((__packed__)) hci_read_local_ver_rp;
-
-#define HCI_OCF_READ_LOCAL_COMMANDS			0x0002
-#define HCI_CMD_READ_LOCAL_COMMANDS			0x1002
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint8_t		commands[HCI_COMMANDS_SIZE];	/* opcode bitmask */
-} __attribute__ ((__packed__)) hci_read_local_commands_rp;
-
-#define HCI_OCF_READ_LOCAL_FEATURES			0x0003
-#define HCI_CMD_READ_LOCAL_FEATURES			0x1003
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;                      /* 0x00 - success */
-	uint8_t		features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/
-} __attribute__ ((__packed__)) hci_read_local_features_rp;
-
-#define HCI_OCF_READ_LOCAL_EXTENDED_FEATURES		0x0004
-#define HCI_CMD_READ_LOCAL_EXTENDED_FEATURES		0x1004
-typedef struct {
-	uint8_t		page;		/* page number */
-} __attribute__ ((__packed__)) hci_read_local_extended_features_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint8_t		page;		/* page number */
-	uint8_t		max_page;	/* maximum page number */
-	uint8_t		features[HCI_FEATURES_SIZE];	/* LMP features */
-} __attribute__ ((__packed__)) hci_read_local_extended_features_rp;
-
-#define HCI_OCF_READ_BUFFER_SIZE			0x0005
-#define HCI_CMD_READ_BUFFER_SIZE			0x1005
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;       /* 0x00 - success */
-	uint16_t	max_acl_size; /* Max. size of ACL packet (bytes) */
-	uint8_t		max_sco_size; /* Max. size of SCO packet (bytes) */
-	uint16_t	num_acl_pkts;  /* Max. number of ACL packets */
-	uint16_t	num_sco_pkts;  /* Max. number of SCO packets */
-} __attribute__ ((__packed__)) hci_read_buffer_size_rp;
-
-/* Read Country Code is deprecated */
-#define HCI_OCF_READ_COUNTRY_CODE			0x0007
-#define HCI_CMD_READ_COUNTRY_CODE			0x1007
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status;       /* 0x00 - success */
-	uint8_t		country_code; /* 0x00 - NAM, EUR, JP; 0x01 - France */
-} __attribute__ ((__packed__)) hci_read_country_code_rp;
-
-#define HCI_OCF_READ_BDADDR				0x0009
-#define HCI_CMD_READ_BDADDR				0x1009
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status; /* 0x00 - success */
-	bdaddr_t	bdaddr; /* unit address */
-} __attribute__ ((__packed__)) hci_read_bdaddr_rp;
-
-/**************************************************************************
- **************************************************************************
- ** OGF 0x05	Status commands and return parameters
- **************************************************************************
- **************************************************************************/
-
-#define HCI_OGF_STATUS				0x05
-
-#define HCI_OCF_READ_FAILED_CONTACT_CNTR		0x0001
-#define HCI_CMD_READ_FAILED_CONTACT_CNTR		0x1401
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_failed_contact_cntr_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint16_t	counter;    /* number of consecutive failed contacts */
-} __attribute__ ((__packed__)) hci_read_failed_contact_cntr_rp;
-
-#define HCI_OCF_RESET_FAILED_CONTACT_CNTR		0x0002
-#define HCI_CMD_RESET_FAILED_CONTACT_CNTR		0x1402
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_reset_failed_contact_cntr_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_reset_failed_contact_cntr_rp;
-
-#define HCI_OCF_READ_LINK_QUALITY			0x0003
-#define HCI_CMD_READ_LINK_QUALITY			0x1403
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_link_quality_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint8_t		quality;    /* higher value means better quality */
-} __attribute__ ((__packed__)) hci_read_link_quality_rp;
-
-#define HCI_OCF_READ_RSSI				0x0005
-#define HCI_CMD_READ_RSSI				0x1405
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_rssi_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	char		rssi;       /* -127 <= rssi <= 127 dB */
-} __attribute__ ((__packed__)) hci_read_rssi_rp;
-
-#define HCI_OCF_READ_AFH_CHANNEL_MAP			0x0006
-#define HCI_CMD_READ_AFH_CHANNEL_MAP			0x1406
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_read_afh_channel_map_cp;
-
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint8_t		mode;       /* AFH mode */
-	uint8_t		map[10];    /* AFH Channel Map */
-} __attribute__ ((__packed__)) hci_read_afh_channel_map_rp;
-
-#define HCI_OCF_READ_CLOCK				0x0007
-#define HCI_CMD_READ_CLOCK				0x1407
-typedef struct {
-	uint16_t	con_handle;	/* connection handle */
-	uint8_t		clock;		/* which clock */
-} __attribute__ ((__packed__)) hci_read_clock_cp;
-
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint16_t	con_handle;	/* connection handle */
-	uint32_t	clock;		/* clock value */
-	uint16_t	accuracy;	/* clock accuracy */
-} __attribute__ ((__packed__)) hci_read_clock_rp;
-
-
-/**************************************************************************
- **************************************************************************
- ** OGF 0x06	Testing commands and return parameters
- **************************************************************************
- **************************************************************************/
-
-#define HCI_OGF_TESTING				0x06
-
-#define HCI_OCF_READ_LOOPBACK_MODE			0x0001
-#define HCI_CMD_READ_LOOPBACK_MODE			0x1801
-/* No command parameter(s) */
-typedef struct {
-	uint8_t		status; /* 0x00 - success */
-	uint8_t		lbmode; /* loopback mode */
-} __attribute__ ((__packed__)) hci_read_loopback_mode_rp;
-
-#define HCI_OCF_WRITE_LOOPBACK_MODE			0x0002
-#define HCI_CMD_WRITE_LOOPBACK_MODE			0x1802
-typedef struct {
-	uint8_t		lbmode; /* loopback mode */
-} __attribute__ ((__packed__)) hci_write_loopback_mode_cp;
-
-typedef hci_status_rp	hci_write_loopback_mode_rp;
-
-#define HCI_OCF_ENABLE_UNIT_UNDER_TEST			0x0003
-#define HCI_CMD_ENABLE_UNIT_UNDER_TEST			0x1803
-/* No command parameter(s) */
-typedef hci_status_rp	hci_enable_unit_under_test_rp;
-
-#define HCI_OCF_WRITE_SIMPLE_PAIRING_DEBUG_MODE		0x0004
-#define HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE		0x1804
-typedef struct {
-	uint8_t		mode;	/* simple pairing debug mode */
-} __attribute__ ((__packed__)) hci_write_simple_pairing_debug_mode_cp;
-
-typedef hci_status_rp	hci_write_simple_pairing_debug_mode_rp;
-
-/**************************************************************************
- **************************************************************************
- ** OGF 0x3e	Bluetooth Logo Testing
- ** OGF 0x3f	Vendor Specific
- **************************************************************************
- **************************************************************************/
-
-#define HCI_OGF_BT_LOGO				0x3e
-#define HCI_OGF_VENDOR				0x3f
-
-/* Ericsson specific FC */
-#define HCI_CMD_ERICSSON_WRITE_PCM_SETTINGS		0xFC07
-#define HCI_CMD_ERICSSON_SET_UART_BAUD_RATE		0xFC09
-#define HCI_CMD_ERICSSON_SET_SCO_DATA_PATH		0xFC1D
-
-/* Cambridge Silicon Radio specific FC */
-#define HCI_CMD_CSR_EXTN				0xFC00
-
-
-/**************************************************************************
- **************************************************************************
- **                         Events and event parameters
- **************************************************************************
- **************************************************************************/
-
-#define HCI_EVENT_INQUIRY_COMPL			0x01
-typedef struct {
-	uint8_t		status; /* 0x00 - success */
-} __attribute__ ((__packed__)) hci_inquiry_compl_ep;
-
-#define HCI_EVENT_INQUIRY_RESULT		0x02
-typedef struct {
-	uint8_t		num_responses;      /* number of responses */
-/*	hci_inquiry_response[num_responses]   -- see below */
-} __attribute__ ((__packed__)) hci_inquiry_result_ep;
-
-typedef struct {
-	bdaddr_t	bdaddr;                   /* unit address */
-	uint8_t		page_scan_rep_mode;       /* page scan rep. mode */
-	uint8_t		page_scan_period_mode;    /* page scan period mode */
-	uint8_t		page_scan_mode;           /* page scan mode */
-	uint8_t		uclass[HCI_CLASS_SIZE];   /* unit class */
-	uint16_t	clock_offset;             /* clock offset */
-} __attribute__ ((__packed__)) hci_inquiry_response;
-
-#define HCI_EVENT_CON_COMPL			0x03
-typedef struct {
-	uint8_t		status;          /* 0x00 - success */
-	uint16_t	con_handle;      /* Connection handle */
-	bdaddr_t	bdaddr;          /* remote unit address */
-	uint8_t		link_type;       /* Link type */
-	uint8_t		encryption_mode; /* Encryption mode */
-} __attribute__ ((__packed__)) hci_con_compl_ep;
-
-#define HCI_EVENT_CON_REQ			0x04
-typedef struct {
-	bdaddr_t	bdaddr;                 /* remote unit address */
-	uint8_t		uclass[HCI_CLASS_SIZE]; /* remote unit class */
-	uint8_t		link_type;              /* link type */
-} __attribute__ ((__packed__)) hci_con_req_ep;
-
-#define HCI_EVENT_DISCON_COMPL			0x05
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint8_t		reason;     /* reason to disconnect */
-} __attribute__ ((__packed__)) hci_discon_compl_ep;
-
-#define HCI_EVENT_AUTH_COMPL			0x06
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_auth_compl_ep;
-
-#define HCI_EVENT_REMOTE_NAME_REQ_COMPL		0x07
-typedef struct {
-	uint8_t		status;                   /* 0x00 - success */
-	bdaddr_t	bdaddr;                   /* remote unit address */
-	char		name[HCI_UNIT_NAME_SIZE]; /* remote unit name */
-} __attribute__ ((__packed__)) hci_remote_name_req_compl_ep;
-
-#define HCI_EVENT_ENCRYPTION_CHANGE		0x08
-typedef struct {
-	uint8_t		status;            /* 0x00 - success */
-	uint16_t	con_handle;        /* Connection handle */
-	uint8_t		encryption_enable; /* 0x00 - disable */
-} __attribute__ ((__packed__)) hci_encryption_change_ep;
-
-#define HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL	0x09
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* Connection handle */
-} __attribute__ ((__packed__)) hci_change_con_link_key_compl_ep;
-
-#define HCI_EVENT_MASTER_LINK_KEY_COMPL		0x0a
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* Connection handle */
-	uint8_t		key_flag;   /* Key flag */
-} __attribute__ ((__packed__)) hci_master_link_key_compl_ep;
-
-#define HCI_EVENT_READ_REMOTE_FEATURES_COMPL	0x0b
-typedef struct {
-	uint8_t		status;                      /* 0x00 - success */
-	uint16_t	con_handle;                  /* Connection handle */
-	uint8_t		features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/
-} __attribute__ ((__packed__)) hci_read_remote_features_compl_ep;
-
-#define HCI_EVENT_READ_REMOTE_VER_INFO_COMPL	0x0c
-typedef struct {
-	uint8_t		status;         /* 0x00 - success */
-	uint16_t	con_handle;     /* Connection handle */
-	uint8_t		lmp_version;    /* LMP version */
-	uint16_t	manufacturer;   /* Hardware manufacturer name */
-	uint16_t	lmp_subversion; /* LMP sub-version */
-} __attribute__ ((__packed__)) hci_read_remote_ver_info_compl_ep;
-
-#define HCI_EVENT_QOS_SETUP_COMPL		0x0d
-typedef struct {
-	uint8_t		status;          /* 0x00 - success */
-	uint16_t	con_handle;      /* connection handle */
-	uint8_t		flags;           /* reserved for future use */
-	uint8_t		service_type;    /* service type */
-	uint32_t	token_rate;      /* bytes per second */
-	uint32_t	peak_bandwidth;  /* bytes per second */
-	uint32_t	latency;         /* microseconds */
-	uint32_t	delay_variation; /* microseconds */
-} __attribute__ ((__packed__)) hci_qos_setup_compl_ep;
-
-#define HCI_EVENT_COMMAND_COMPL			0x0e
-typedef struct {
-	uint8_t		num_cmd_pkts; /* # of HCI command packets */
-	uint16_t	opcode;       /* command OpCode */
-	/* command return parameters (if any) */
-} __attribute__ ((__packed__)) hci_command_compl_ep;
-
-#define HCI_EVENT_COMMAND_STATUS		0x0f
-typedef struct {
-	uint8_t		status;       /* 0x00 - pending */
-	uint8_t		num_cmd_pkts; /* # of HCI command packets */
-	uint16_t	opcode;       /* command OpCode */
-} __attribute__ ((__packed__)) hci_command_status_ep;
-
-#define HCI_EVENT_HARDWARE_ERROR		0x10
-typedef struct {
-	uint8_t		hardware_code; /* hardware error code */
-} __attribute__ ((__packed__)) hci_hardware_error_ep;
-
-#define HCI_EVENT_FLUSH_OCCUR			0x11
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_flush_occur_ep;
-
-#define HCI_EVENT_ROLE_CHANGE			0x12
-typedef struct {
-	uint8_t		status; /* 0x00 - success */
-	bdaddr_t	bdaddr; /* address of remote unit */
-	uint8_t		role;   /* new connection role */
-} __attribute__ ((__packed__)) hci_role_change_ep;
-
-#define HCI_EVENT_NUM_COMPL_PKTS		0x13
-typedef struct {
-	uint8_t		num_con_handles; /* # of connection handles */
-/* these are repeated "num_con_handles" times
-	uint16_t	con_handle; --- connection handle(s)
-	uint16_t	compl_pkts; --- # of completed packets */
-} __attribute__ ((__packed__)) hci_num_compl_pkts_ep;
-
-#define HCI_EVENT_MODE_CHANGE			0x14
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint8_t		unit_mode;  /* remote unit mode */
-	uint16_t	interval;   /* interval * 0.625 msec */
-} __attribute__ ((__packed__)) hci_mode_change_ep;
-
-#define HCI_EVENT_RETURN_LINK_KEYS		0x15
-typedef struct {
-	uint8_t		num_keys; /* # of keys */
-/* these are repeated "num_keys" times
-	bdaddr_t	bdaddr;               --- remote address(es)
-	uint8_t		key[HCI_KEY_SIZE]; --- key(s) */
-} __attribute__ ((__packed__)) hci_return_link_keys_ep;
-
-#define HCI_EVENT_PIN_CODE_REQ			0x16
-typedef struct {
-	bdaddr_t	bdaddr; /* remote unit address */
-} __attribute__ ((__packed__)) hci_pin_code_req_ep;
-
-#define HCI_EVENT_LINK_KEY_REQ			0x17
-typedef struct {
-	bdaddr_t	bdaddr; /* remote unit address */
-} __attribute__ ((__packed__)) hci_link_key_req_ep;
-
-#define HCI_EVENT_LINK_KEY_NOTIFICATION		0x18
-typedef struct {
-	bdaddr_t	bdaddr;            /* remote unit address */
-	uint8_t		key[HCI_KEY_SIZE]; /* link key */
-	uint8_t		key_type;          /* type of the key */
-} __attribute__ ((__packed__)) hci_link_key_notification_ep;
-
-#define HCI_EVENT_LOOPBACK_COMMAND		0x19
-typedef hci_cmd_hdr_t	hci_loopback_command_ep;
-
-#define HCI_EVENT_DATA_BUFFER_OVERFLOW		0x1a
-typedef struct {
-	uint8_t		link_type; /* Link type */
-} __attribute__ ((__packed__)) hci_data_buffer_overflow_ep;
-
-#define HCI_EVENT_MAX_SLOT_CHANGE		0x1b
-typedef struct {
-	uint16_t	con_handle;    /* connection handle */
-	uint8_t		lmp_max_slots; /* Max. # of slots allowed */
-} __attribute__ ((__packed__)) hci_max_slot_change_ep;
-
-#define HCI_EVENT_READ_CLOCK_OFFSET_COMPL	0x1c
-typedef struct {
-	uint8_t		status;       /* 0x00 - success */
-	uint16_t	con_handle;   /* Connection handle */
-	uint16_t	clock_offset; /* Clock offset */
-} __attribute__ ((__packed__)) hci_read_clock_offset_compl_ep;
-
-#define HCI_EVENT_CON_PKT_TYPE_CHANGED		0x1d
-typedef struct {
-	uint8_t		status;     /* 0x00 - success */
-	uint16_t	con_handle; /* connection handle */
-	uint16_t	pkt_type;   /* packet type */
-} __attribute__ ((__packed__)) hci_con_pkt_type_changed_ep;
-
-#define HCI_EVENT_QOS_VIOLATION			0x1e
-typedef struct {
-	uint16_t	con_handle; /* connection handle */
-} __attribute__ ((__packed__)) hci_qos_violation_ep;
-
-/* Page Scan Mode Change Event is deprecated */
-#define HCI_EVENT_PAGE_SCAN_MODE_CHANGE		0x1f
-typedef struct {
-	bdaddr_t	bdaddr;         /* destination address */
-	uint8_t		page_scan_mode; /* page scan mode */
-} __attribute__ ((__packed__)) hci_page_scan_mode_change_ep;
-
-#define HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE	0x20
-typedef struct {
-	bdaddr_t	bdaddr;             /* destination address */
-	uint8_t		page_scan_rep_mode; /* page scan repetition mode */
-} __attribute__ ((__packed__)) hci_page_scan_rep_mode_change_ep;
-
-#define HCI_EVENT_FLOW_SPECIFICATION_COMPL	0x21
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint16_t	con_handle;	/* connection handle */
-	uint8_t		flags;		/* reserved */
-	uint8_t		direction;	/* flow direction */
-	uint8_t		type;		/* service type */
-	uint32_t	token_rate;	/* token rate */
-	uint32_t	bucket_size;	/* token bucket size */
-	uint32_t	peak_bandwidth;	/* peak bandwidth */
-	uint32_t	latency;	/* access latency */
-} __attribute__ ((__packed__)) hci_flow_specification_compl_ep;
-
-#define HCI_EVENT_RSSI_RESULT			0x22
-typedef struct {
-	uint8_t		num_responses;      /* number of responses */
-/*	hci_rssi_response[num_responses]   -- see below */
-} __attribute__ ((__packed__)) hci_rssi_result_ep;
-
-typedef struct {
-	bdaddr_t	bdaddr;			/* unit address */
-	uint8_t		page_scan_rep_mode;	/* page scan rep. mode */
-	uint8_t		blank;			/* reserved */
-	uint8_t		uclass[HCI_CLASS_SIZE];	/* unit class */
-	uint16_t	clock_offset;		/* clock offset */
-	int8_t		rssi;			/* rssi */
-} __attribute__ ((__packed__)) hci_rssi_response;
-
-#define HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES	0x23
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint16_t	con_handle;	/* connection handle */
-	uint8_t		page;		/* page number */
-	uint8_t		max;		/* max page number */
-	uint8_t		features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/
-} __attribute__ ((__packed__)) hci_read_remote_extended_features_ep;
-
-#define HCI_EVENT_SCO_CON_COMPL			0x2c
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint16_t	con_handle;	/* connection handle */
-	bdaddr_t	bdaddr;		/* unit address */
-	uint8_t		link_type;	/* link type */
-	uint8_t		interval;	/* transmission interval */
-	uint8_t		window;		/* retransmission window */
-	uint16_t	rxlen;		/* rx packet length */
-	uint16_t	txlen;		/* tx packet length */
-	uint8_t		mode;		/* air mode */
-} __attribute__ ((__packed__)) hci_sco_con_compl_ep;
-
-#define HCI_EVENT_SCO_CON_CHANGED		0x2d
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint16_t	con_handle;	/* connection handle */
-	uint8_t		interval;	/* transmission interval */
-	uint8_t		window;		/* retransmission window */
-	uint16_t	rxlen;		/* rx packet length */
-	uint16_t	txlen;		/* tx packet length */
-} __attribute__ ((__packed__)) hci_sco_con_changed_ep;
-
-#define HCI_EVENT_SNIFF_SUBRATING		0x2e
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint16_t	con_handle;	/* connection handle */
-	uint16_t	tx_latency;	/* max transmit latency */
-	uint16_t	rx_latency;	/* max receive latency */
-	uint16_t	remote_timeout;	/* remote timeout */
-	uint16_t	local_timeout;	/* local timeout */
-} __attribute__ ((__packed__)) hci_sniff_subrating_ep;
-
-#define HCI_EVENT_EXTENDED_RESULT		0x2f
-typedef struct {
-	uint8_t		num_responses;	/* must be 0x01 */
-	bdaddr_t	bdaddr;		/* remote device address */
-	uint8_t		page_scan_rep_mode;
-	uint8_t		reserved;
-	uint8_t		uclass[HCI_CLASS_SIZE];
-	uint16_t	clock_offset;
-	int8_t		rssi;
-	uint8_t		response[240];	/* extended inquiry response */
-} __attribute__ ((__packed__)) hci_extended_result_ep;
-
-#define HCI_EVENT_ENCRYPTION_KEY_REFRESH	0x30
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	uint16_t	con_handle;	/* connection handle */
-} __attribute__ ((__packed__)) hci_encryption_key_refresh_ep;
-
-#define HCI_EVENT_IO_CAPABILITY_REQ		0x31
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote device address */
-} __attribute__ ((__packed__)) hci_io_capability_req_ep;
-
-#define HCI_EVENT_IO_CAPABILITY_RSP		0x32
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote device address */
-	uint8_t		io_capability;
-	uint8_t		oob_data_present;
-	uint8_t		auth_requirement;
-} __attribute__ ((__packed__)) hci_io_capability_rsp_ep;
-
-#define HCI_EVENT_USER_CONFIRM_REQ		0x33
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote device address */
-	uint32_t	value;		/* 000000 - 999999 */
-} __attribute__ ((__packed__)) hci_user_confirm_req_ep;
-
-#define HCI_EVENT_USER_PASSKEY_REQ		0x34
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote device address */
-} __attribute__ ((__packed__)) hci_user_passkey_req_ep;
-
-#define HCI_EVENT_REMOTE_OOB_DATA_REQ		0x35
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote device address */
-} __attribute__ ((__packed__)) hci_remote_oob_data_req_ep;
-
-#define HCI_EVENT_SIMPLE_PAIRING_COMPL		0x36
-typedef struct {
-	uint8_t		status;		/* 0x00 - success */
-	bdaddr_t	bdaddr;		/* remote device address */
-} __attribute__ ((__packed__)) hci_simple_pairing_compl_ep;
-
-#define HCI_EVENT_LINK_SUPERVISION_TO_CHANGED	0x38
-typedef struct {
-	uint16_t	con_handle;	/* connection handle */
-	uint16_t	timeout;	/* link supervision timeout */
-} __attribute__ ((__packed__)) hci_link_supervision_to_changed_ep;
-
-#define HCI_EVENT_ENHANCED_FLUSH_COMPL		0x39
-typedef struct {
-	uint16_t	con_handle;	/* connection handle */
-} __attribute__ ((__packed__)) hci_enhanced_flush_compl_ep;
-
-#define HCI_EVENT_USER_PASSKEY_NOTIFICATION	0x3b
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote device address */
-	uint32_t	value;		/* 000000 - 999999 */
-} __attribute__ ((__packed__)) hci_user_passkey_notification_ep;
-
-#define HCI_EVENT_KEYPRESS_NOTIFICATION		0x3c
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote device address */
-	uint8_t		notification_type;
-} __attribute__ ((__packed__)) hci_keypress_notification_ep;
-
-#define HCI_EVENT_REMOTE_FEATURES_NOTIFICATION	0x3d
-typedef struct {
-	bdaddr_t	bdaddr;		/* remote device address */
-	uint8_t		features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/
-} __attribute__ ((__packed__)) hci_remote_features_notification_ep;
-
-#define HCI_EVENT_BT_LOGO			0xfe
-
-#define HCI_EVENT_VENDOR			0xff
-
-/**************************************************************************
- **************************************************************************
- **                 HCI Socket Definitions
- **************************************************************************
- **************************************************************************/
-
-/* HCI socket options */
-#define SO_HCI_EVT_FILTER		1	/* get/set event filter */
-#define SO_HCI_PKT_FILTER		2	/* get/set packet filter */
-#define SO_HCI_DIRECTION		3	/* packet direction indicator */
-
-/* Control Messages */
-#define SCM_HCI_DIRECTION		SO_HCI_DIRECTION
-
-/*
- * HCI socket filter and get/set routines
- *
- * for ease of use, we filter 256 possible events/packets
- */
-struct hci_filter {
-	uint32_t	mask[8];	/* 256 bits */
-};
-
-static __inline void
-hci_filter_set(uint8_t bit, struct hci_filter *filter)
-{
-	uint8_t off = bit - 1;
-
-	off >>= 5;
-	filter->mask[off] |= (1 << ((bit - 1) & 0x1f));
-}
-
-static __inline void
-hci_filter_clr(uint8_t bit, struct hci_filter *filter)
-{
-	uint8_t off = bit - 1;
-
-	off >>= 5;
-	filter->mask[off] &= ~(1 << ((bit - 1) & 0x1f));
-}
-
-static __inline int
-hci_filter_test(uint8_t bit, struct hci_filter *filter)
-{
-	uint8_t off = bit - 1;
-
-	off >>= 5;
-	return (filter->mask[off] & (1 << ((bit - 1) & 0x1f)));
-}
-
-/*
- * HCI socket ioctl's
- *
- * Apart from GBTINFOA, these are all indexed on the unit name
- */
-
-#define SIOCGBTINFO	_IOWR('b',  5, struct btreq) /* get unit info */
-#define SIOCGBTINFOA	_IOWR('b',  6, struct btreq) /* get info by address */
-#define SIOCNBTINFO	_IOWR('b',  7, struct btreq) /* next unit info */
-
-#define SIOCSBTFLAGS	_IOWR('b',  8, struct btreq) /* set unit flags */
-#define SIOCSBTPOLICY	_IOWR('b',  9, struct btreq) /* set unit link policy */
-#define SIOCSBTPTYPE	_IOWR('b', 10, struct btreq) /* set unit packet type */
-
-#define SIOCGBTSTATS	_IOWR('b', 11, struct btreq) /* get unit statistics */
-#define SIOCZBTSTATS	_IOWR('b', 12, struct btreq) /* zero unit statistics */
-
-#define SIOCBTDUMP	 _IOW('b', 13, struct btreq) /* print debug info */
-#define SIOCSBTSCOMTU	_IOWR('b', 17, struct btreq) /* set sco_mtu value */
-
-struct bt_stats {
-	uint32_t	err_tx;
-	uint32_t	err_rx;
-	uint32_t	cmd_tx;
-	uint32_t	evt_rx;
-	uint32_t	acl_tx;
-	uint32_t	acl_rx;
-	uint32_t	sco_tx;
-	uint32_t	sco_rx;
-	uint32_t	byte_tx;
-	uint32_t	byte_rx;
-};
-
-struct btreq {
-	char	btr_name[HCI_DEVNAME_SIZE];	/* device name */
-
-	union {
-	    struct {
-		bdaddr_t btri_bdaddr;		/* device bdaddr */
-		uint16_t btri_flags;		/* flags */
-		uint16_t btri_num_cmd;		/* # of free cmd buffers */
-		uint16_t btri_num_acl;		/* # of free ACL buffers */
-		uint16_t btri_num_sco;		/* # of free SCO buffers */
-		uint16_t btri_acl_mtu;		/* ACL mtu */
-		uint16_t btri_sco_mtu;		/* SCO mtu */
-		uint16_t btri_link_policy;	/* Link Policy */
-		uint16_t btri_packet_type;	/* Packet Type */
-	    } btri;
-	    struct bt_stats btrs;   /* unit stats */
-	} btru;
-};
-
-#define btr_flags	btru.btri.btri_flags
-#define btr_bdaddr	btru.btri.btri_bdaddr
-#define btr_num_cmd	btru.btri.btri_num_cmd
-#define btr_num_acl	btru.btri.btri_num_acl
-#define btr_num_sco	btru.btri.btri_num_sco
-#define btr_acl_mtu	btru.btri.btri_acl_mtu
-#define btr_sco_mtu	btru.btri.btri_sco_mtu
-#define btr_link_policy btru.btri.btri_link_policy
-#define btr_packet_type btru.btri.btri_packet_type
-#define btr_stats	btru.btrs
-
-/* hci_unit & btr_flags */
-#define BTF_UP			(1<<0)	/* unit is up */
-#define BTF_RUNNING		(1<<1)	/* unit is running */
-#define BTF_XMIT_CMD		(1<<2)	/* unit is transmitting CMD packets */
-#define BTF_XMIT_ACL		(1<<3)	/* unit is transmitting ACL packets */
-#define BTF_XMIT_SCO		(1<<4)	/* unit is transmitting SCO packets */
-#define BTF_XMIT		(BTF_XMIT_CMD | BTF_XMIT_ACL | BTF_XMIT_SCO)
-#define BTF_INIT_BDADDR		(1<<5)	/* waiting for bdaddr */
-#define BTF_INIT_BUFFER_SIZE	(1<<6)	/* waiting for buffer size */
-#define BTF_INIT_FEATURES	(1<<7)	/* waiting for features */
-#define BTF_POWER_UP_NOOP	(1<<8)	/* should wait for No-op on power up */
-#define BTF_INIT_COMMANDS	(1<<9)	/* waiting for supported commands */
-
-#define BTF_INIT		(BTF_INIT_BDADDR	\
-				| BTF_INIT_BUFFER_SIZE	\
-				| BTF_INIT_FEATURES	\
-				| BTF_INIT_COMMANDS)
-
-/**************************************************************************
- **************************************************************************
- **                 HCI Kernel Definitions
- **************************************************************************
- **************************************************************************/
-
-#ifdef _KERNEL
-
-#include <net/if.h>
-#include <net/if_var.h>		/* for struct ifqueue */
-
-struct l2cap_channel;
-struct mbuf;
-struct sco_pcb;
-struct socket;
-
-/* global HCI kernel variables */
-
-/* sysctl variables */
-extern int hci_memo_expiry;
-extern int hci_acl_expiry;
-extern int hci_sendspace, hci_recvspace;
-extern int hci_eventq_max, hci_aclrxq_max, hci_scorxq_max;
-
-/*
- * HCI Connection Information
- */
-struct hci_link {
-	struct hci_unit		*hl_unit;	/* our unit */
-	TAILQ_ENTRY(hci_link)	 hl_next;	/* next link on unit */
-
-	/* common info */
-	uint16_t		 hl_state;	/* connection state */
-	uint16_t		 hl_flags;	/* link flags */
-	bdaddr_t		 hl_bdaddr;	/* dest address */
-	uint16_t		 hl_handle;	/* connection handle */
-	uint8_t			 hl_type;	/* link type */
-
-	/* ACL link info */
-	uint8_t			 hl_lastid;	/* last id used */
-	uint16_t		 hl_refcnt;	/* reference count */
-	uint16_t		 hl_mtu;	/* signalling mtu for link */
-	uint16_t		 hl_flush;	/* flush timeout */
-	uint16_t		 hl_clock;	/* remote clock offset */
-
-	TAILQ_HEAD(,l2cap_pdu)	 hl_txq;	/* queue of outgoing PDUs */
-	int			 hl_txqlen;	/* number of fragments */
-	struct mbuf		*hl_rxp;	/* incoming PDU (accumulating)*/
-	struct callout		 hl_expire;	/* connection expiry timer */
-	TAILQ_HEAD(,l2cap_req)	 hl_reqs;	/* pending requests */
-
-	/* SCO link info */
-	struct hci_link		*hl_link;	/* SCO ACL link */
-	struct sco_pcb		*hl_sco;	/* SCO pcb */
-	struct ifqueue		 hl_data;	/* SCO outgoing data */
-};
-
-/* hci_link state */
-#define HCI_LINK_CLOSED		0  /* closed */
-#define HCI_LINK_WAIT_CONNECT	1  /* waiting to connect */
-#define HCI_LINK_WAIT_AUTH	2  /* waiting for auth */
-#define HCI_LINK_WAIT_ENCRYPT	3  /* waiting for encrypt */
-#define HCI_LINK_WAIT_SECURE	4  /* waiting for secure */
-#define HCI_LINK_OPEN		5  /* ready and willing */
-#define HCI_LINK_BLOCK		6  /* open but blocking (see hci_acl_start) */
-
-/* hci_link flags */
-#define HCI_LINK_AUTH_REQ	(1<<0)  /* authentication requested */
-#define HCI_LINK_ENCRYPT_REQ	(1<<1)  /* encryption requested */
-#define HCI_LINK_SECURE_REQ	(1<<2)	/* secure link requested */
-#define HCI_LINK_AUTH		(1<<3)	/* link is authenticated */
-#define HCI_LINK_ENCRYPT	(1<<4)	/* link is encrypted */
-#define HCI_LINK_SECURE		(1<<5)	/* link is secured */
-
-/*
- * Bluetooth Memo
- *	cached device information for remote devices that this unit has seen
- */
-struct hci_memo {
-	struct timeval		time;		/* time of last response */
-	bdaddr_t		bdaddr;
-	uint8_t			page_scan_rep_mode;
-	uint8_t			page_scan_mode;
-	uint16_t		clock_offset;
-	LIST_ENTRY(hci_memo)	next;
-};
-
-/*
- * The Bluetooth HCI interface attachment structure
- */
-struct hci_if {
-	int	(*enable)(device_t);
-	void	(*disable)(device_t);
-	void	(*output_cmd)(device_t, struct mbuf *);
-	void	(*output_acl)(device_t, struct mbuf *);
-	void	(*output_sco)(device_t, struct mbuf *);
-	void	(*get_stats)(device_t, struct bt_stats *, int);
-};
-
-/*
- * The Bluetooth HCI device unit structure
- */
-struct hci_unit {
-	device_t	 hci_dev;		/* bthci handle */
-#if 0 /* not yet */
-	device_t	 hci_bthub;		/* bthub(4) handle */
-#endif
-	const struct hci_if *hci_if;		/* bthci driver interface */
-
-	/* device info */
-	bdaddr_t	 hci_bdaddr;		/* device address */
-	uint16_t	 hci_flags;		/* see BTF_ above */
-
-	uint16_t	 hci_packet_type;	/* packet types */
-	uint16_t	 hci_acl_mask;		/* ACL packet capabilities */
-	uint16_t	 hci_sco_mask;		/* SCO packet capabilities */
-
-	uint16_t	 hci_link_policy;	/* link policy */
-	uint16_t	 hci_lmp_mask;		/* link policy capabilities */
-
-	uint8_t		 hci_cmds[HCI_COMMANDS_SIZE]; /* opcode bitmask */
-
-	/* flow control */
-	uint16_t	 hci_max_acl_size;	/* ACL payload mtu */
-	uint16_t	 hci_num_acl_pkts;	/* free ACL packet buffers */
-	uint8_t		 hci_num_cmd_pkts;	/* free CMD packet buffers */
-	uint8_t		 hci_max_sco_size;	/* SCO payload mtu */
-	uint16_t	 hci_num_sco_pkts;	/* free SCO packet buffers */
-
-	TAILQ_HEAD(,hci_link)	hci_links;	/* list of ACL/SCO links */
-	LIST_HEAD(,hci_memo)	hci_memos;	/* cached memo list */
-
-	/* input queues */
-	void			*hci_rxint;	/* receive interrupt cookie */
-	struct lock		 hci_devlock;	/* device queue lock */
-	struct ifqueue		 hci_eventq;	/* Event queue */
-	struct ifqueue		 hci_aclrxq;	/* ACL rx queue */
-	struct ifqueue		 hci_scorxq;	/* SCO rx queue */
-	uint16_t		 hci_eventqlen;	/* Event queue length */
-	uint16_t		 hci_aclrxqlen;	/* ACL rx queue length */
-	uint16_t		 hci_scorxqlen;	/* SCO rx queue length */
-
-	/* output queues */
-	struct ifqueue		 hci_cmdwait;	/* pending commands */
-	struct ifqueue		 hci_scodone;	/* SCO done queue */
-
-	TAILQ_ENTRY(hci_unit) hci_next;
-};
-
-extern TAILQ_HEAD(hci_unit_list, hci_unit) hci_unit_list;
-
-/*
- * HCI layer function prototypes
- */
-union netmsg;
-
-/* hci_event.c */
-void hci_event(struct mbuf *, struct hci_unit *);
-
-/* hci_ioctl.c */
-int hci_ioctl(unsigned long, void *, struct proc *);
-
-/* hci_link.c */
-struct hci_link *hci_acl_open(struct hci_unit *, bdaddr_t *);
-struct hci_link *hci_acl_newconn(struct hci_unit *, bdaddr_t *);
-void hci_acl_close(struct hci_link *, int);
-void hci_acl_timeout(void *);
-int hci_acl_setmode(struct hci_link *);
-void hci_acl_linkmode(struct hci_link *);
-void hci_acl_recv(struct mbuf *, struct hci_unit *);
-int hci_acl_send(struct mbuf *, struct hci_link *, struct l2cap_channel *);
-void hci_acl_start(struct hci_link *);
-void hci_acl_complete(struct hci_link *, int);
-struct hci_link *hci_sco_newconn(struct hci_unit *, bdaddr_t *);
-void hci_sco_recv(struct mbuf *, struct hci_unit *);
-void hci_sco_start(struct hci_link *);
-void hci_sco_complete(struct hci_link *, int);
-struct hci_link *hci_link_alloc(struct hci_unit *);
-void hci_link_free(struct hci_link *, int);
-struct hci_link *hci_link_lookup_state(struct hci_unit *, uint16_t, uint16_t);
-struct hci_link *hci_link_lookup_bdaddr(struct hci_unit *, bdaddr_t *, uint16_t);
-struct hci_link *hci_link_lookup_handle(struct hci_unit *, uint16_t);
-
-/* hci_misc.c */
-int hci_route_lookup(bdaddr_t *, bdaddr_t *);
-struct hci_memo *hci_memo_find(struct hci_unit *, bdaddr_t *);
-struct hci_memo *hci_memo_new(struct hci_unit *, bdaddr_t *);
-void hci_memo_free(struct hci_memo *);
-
-/* hci_socket.c */
-void hci_drop(void *);
-int hci_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *);
-void hci_ctloutput(union netmsg *);
-void hci_mtap(struct mbuf *, struct hci_unit *);
-
-/* hci_unit.c */
-struct hci_unit *hci_attach(const struct hci_if *, device_t, uint16_t);
-void hci_detach(struct hci_unit *);
-int hci_enable(struct hci_unit *);
-void hci_disable(struct hci_unit *);
-struct hci_unit *hci_unit_lookup(bdaddr_t *);
-int hci_send_cmd(struct hci_unit *, uint16_t, void *, uint8_t);
-int hci_input_event(struct hci_unit *, struct mbuf *);
-int hci_input_acl(struct hci_unit *, struct mbuf *);
-int hci_input_sco(struct hci_unit *, struct mbuf *);
-int hci_complete_sco(struct hci_unit *, struct mbuf *);
-void hci_output_cmd(struct hci_unit *, struct mbuf *);
-void hci_output_acl(struct hci_unit *, struct mbuf *);
-void hci_output_sco(struct hci_unit *, struct mbuf *);
-void hci_intr(void *);
-void btintr(union netmsg *);
-
-/* XXX mimic NetBSD for now, although we don't have these interfaces */
-#define M_GETCTX(m, t)	((t)(m)->m_pkthdr.rcvif)
-#define M_SETCTX(m, c)	((m)->m_pkthdr.rcvif = (void *)(c))
-#define EPASSTHROUGH ENOTTY	/* XXX */
-
-#endif	/* _KERNEL */
-
-#endif /* _NETBT_HCI_H_ */
diff --git a/sys/netbt/hci_event.c b/sys/netbt/hci_event.c
deleted file mode 100644
index 8d3035def0..0000000000
--- a/sys/netbt/hci_event.c
+++ /dev/null
@@ -1,1086 +0,0 @@
-/* $OpenBSD: src/sys/netbt/hci_event.c,v 1.7 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: hci_event.c,v 1.14 2008/02/10 17:40:54 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/systm.h>
-#include <sys/endian.h>
-#include <sys/bus.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/sco.h>
-
-static void hci_event_inquiry_result(struct hci_unit *, struct mbuf *);
-static void hci_event_rssi_result(struct hci_unit *, struct mbuf *);
-static void hci_event_command_status(struct hci_unit *, struct mbuf *);
-static void hci_event_command_compl(struct hci_unit *, struct mbuf *);
-static void hci_event_con_compl(struct hci_unit *, struct mbuf *);
-static void hci_event_discon_compl(struct hci_unit *, struct mbuf *);
-static void hci_event_con_req(struct hci_unit *, struct mbuf *);
-static void hci_event_num_compl_pkts(struct hci_unit *, struct mbuf *);
-static void hci_event_auth_compl(struct hci_unit *, struct mbuf *);
-static void hci_event_encryption_change(struct hci_unit *, struct mbuf *);
-static void hci_event_change_con_link_key_compl(struct hci_unit *, struct mbuf *);
-static void hci_event_read_clock_offset_compl(struct hci_unit *, struct mbuf *);
-static void hci_cmd_read_bdaddr(struct hci_unit *, struct mbuf *);
-static void hci_cmd_read_buffer_size(struct hci_unit *, struct mbuf *);
-static void hci_cmd_read_local_features(struct hci_unit *, struct mbuf *);
-static void hci_cmd_read_local_ver(struct hci_unit *, struct mbuf *);
-static void hci_cmd_read_local_commands(struct hci_unit *, struct mbuf *);
-static void hci_cmd_reset(struct hci_unit *, struct mbuf *);
-
-#ifdef BLUETOOTH_DEBUG
-int bluetooth_debug = BLUETOOTH_DEBUG;
-
-static const char *hci_eventnames[] = {
-/* 0x00 */ "NULL",
-/* 0x01 */ "INQUIRY COMPLETE",
-/* 0x02 */ "INQUIRY RESULT",
-/* 0x03 */ "CONN COMPLETE",
-/* 0x04 */ "CONN REQ",
-/* 0x05 */ "DISCONN COMPLETE",
-/* 0x06 */ "AUTH COMPLETE",
-/* 0x07 */ "REMOTE NAME REQ COMPLETE",
-/* 0x08 */ "ENCRYPTION CHANGE",
-/* 0x09 */ "CHANGE CONN LINK KEY COMPLETE",
-/* 0x0a */ "MASTER LINK KEY COMPLETE",
-/* 0x0b */ "READ REMOTE FEATURES COMPLETE",
-/* 0x0c */ "READ REMOTE VERSION INFO COMPLETE",
-/* 0x0d */ "QoS SETUP COMPLETE",
-/* 0x0e */ "COMMAND COMPLETE",
-/* 0x0f */ "COMMAND STATUS",
-/* 0x10 */ "HARDWARE ERROR",
-/* 0x11 */ "FLUSH OCCUR",
-/* 0x12 */ "ROLE CHANGE",
-/* 0x13 */ "NUM COMPLETED PACKETS",
-/* 0x14 */ "MODE CHANGE",
-/* 0x15 */ "RETURN LINK KEYS",
-/* 0x16 */ "PIN CODE REQ",
-/* 0x17 */ "LINK KEY REQ",
-/* 0x18 */ "LINK KEY NOTIFICATION",
-/* 0x19 */ "LOOPBACK COMMAND",
-/* 0x1a */ "DATA BUFFER OVERFLOW",
-/* 0x1b */ "MAX SLOT CHANGE",
-/* 0x1c */ "READ CLOCK OFFSET COMPLETE",
-/* 0x1d */ "CONN PKT TYPE CHANGED",
-/* 0x1e */ "QOS VIOLATION",
-/* 0x1f */ "PAGE SCAN MODE CHANGE",
-/* 0x20 */ "PAGE SCAN REP MODE CHANGE",
-/* 0x21 */ "FLOW SPECIFICATION COMPLETE",
-/* 0x22 */ "RSSI RESULT",
-/* 0x23 */ "READ REMOTE EXT FEATURES",
-/* 0x24 */ "UNKNOWN",
-/* 0x25 */ "UNKNOWN",
-/* 0x26 */ "UNKNOWN",
-/* 0x27 */ "UNKNOWN",
-/* 0x28 */ "UNKNOWN",
-/* 0x29 */ "UNKNOWN",
-/* 0x2a */ "UNKNOWN",
-/* 0x2b */ "UNKNOWN",
-/* 0x2c */ "SCO CON COMPLETE",
-/* 0x2d */ "SCO CON CHANGED",
-/* 0x2e */ "SNIFF SUBRATING",
-/* 0x2f */ "EXTENDED INQUIRY RESULT",
-/* 0x30 */ "ENCRYPTION KEY REFRESH",
-/* 0x31 */ "IO CAPABILITY REQUEST",
-/* 0x32 */ "IO CAPABILITY RESPONSE",
-/* 0x33 */ "USER CONFIRM REQUEST",
-/* 0x34 */ "USER PASSKEY REQUEST",
-/* 0x35 */ "REMOTE OOB DATA REQUEST",
-/* 0x36 */ "SIMPLE PAIRING COMPLETE",
-/* 0x37 */ "UNKNOWN",
-/* 0x38 */ "LINK SUPERVISION TIMEOUT CHANGED",
-/* 0x39 */ "ENHANCED FLUSH COMPLETE",
-/* 0x3a */ "UNKNOWN",
-/* 0x3b */ "USER PASSKEY NOTIFICATION",
-/* 0x3c */ "KEYPRESS NOTIFICATION",
-/* 0x3d */ "REMOTE HOST FEATURES NOTIFICATION",
-};
-
-static const char *
-hci_eventstr(unsigned int event)
-{
-
-	if (event < NELEM(hci_eventnames))
-		return hci_eventnames[event];
-
-	switch (event) {
-	case HCI_EVENT_BT_LOGO:		/* 0xfe */
-		return "BT_LOGO";
-
-	case HCI_EVENT_VENDOR:		/* 0xff */
-		return "VENDOR";
-	}
-
-	return "UNKNOWN";
-}
-#endif	/* BLUETOOTH_DEBUG */
-
-/*
- * process HCI Events
- *
- * We will free the mbuf at the end, no need for any sub
- * functions to handle that. We kind of assume that the
- * device sends us valid events.
- */
-void
-hci_event(struct mbuf *m, struct hci_unit *unit)
-{
-	hci_event_hdr_t hdr;
-
-	KKASSERT(m->m_flags & M_PKTHDR);
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(hdr));
-	m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
-	m_adj(m, sizeof(hdr));
-
-	KKASSERT(hdr.type == HCI_EVENT_PKT);
-
-	DPRINTFN(1, "(%s) event %s\n",
-	    device_get_nameunit(unit->hci_dev), hci_eventstr(hdr.event));
-
-	switch(hdr.event) {
-	case HCI_EVENT_COMMAND_STATUS:
-		hci_event_command_status(unit, m);
-		break;
-
-	case HCI_EVENT_COMMAND_COMPL:
-		hci_event_command_compl(unit, m);
-		break;
-
-	case HCI_EVENT_NUM_COMPL_PKTS:
-		hci_event_num_compl_pkts(unit, m);
-		break;
-
-	case HCI_EVENT_INQUIRY_RESULT:
-		hci_event_inquiry_result(unit, m);
-		break;
-
-	case HCI_EVENT_RSSI_RESULT:
-		hci_event_rssi_result(unit, m);
-		break;
-
-	case HCI_EVENT_CON_COMPL:
-		hci_event_con_compl(unit, m);
-		break;
-
-	case HCI_EVENT_DISCON_COMPL:
-		hci_event_discon_compl(unit, m);
-		break;
-
-	case HCI_EVENT_CON_REQ:
-		hci_event_con_req(unit, m);
-		break;
-
-	case HCI_EVENT_AUTH_COMPL:
-		hci_event_auth_compl(unit, m);
-		break;
-
-	case HCI_EVENT_ENCRYPTION_CHANGE:
-		hci_event_encryption_change(unit, m);
-		break;
-
-	case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL:
-		hci_event_change_con_link_key_compl(unit, m);
-		break;
-
-	case HCI_EVENT_READ_CLOCK_OFFSET_COMPL:
-		hci_event_read_clock_offset_compl(unit, m);
-		break;
-
-	default:
-		break;
-	}
-
-	m_freem(m);
-}
-
-/*
- * Command Status
- *
- * Update our record of num_cmd_pkts then post-process any pending commands
- * and optionally restart cmd output on the unit.
- */
-static void
-hci_event_command_status(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_command_status_ep ep;
-	struct hci_link *link;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n",
-		device_get_nameunit(unit->hci_dev),
-		HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)),
-		ep.status,
-		ep.num_cmd_pkts);
-
-	if (ep.status > 0)
-		kprintf("%s: CommandStatus opcode (%03x|%04x) failed "
-		    "(status=0x%02x)\n", device_get_nameunit(unit->hci_dev),
-		    HCI_OGF(letoh16(ep.opcode)),
-		    HCI_OCF(letoh16(ep.opcode)), ep.status);
-
-	unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
-
-	/*
-	 * post processing of pending commands
-	 */
-	switch(letoh16(ep.opcode)) {
-	case HCI_CMD_CREATE_CON:
-		switch (ep.status) {
-		case 0x12:	/* Invalid HCI command parameters */
-			DPRINTF("(%s) Invalid HCI command parameters\n",
-			    device_get_nameunit(unit->hci_dev));
-			while ((link = hci_link_lookup_state(unit,
-			    HCI_LINK_ACL, HCI_LINK_WAIT_CONNECT)) != NULL)
-				hci_link_free(link, ECONNABORTED);
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-
-	while (unit->hci_num_cmd_pkts > 0 && !IF_QEMPTY(&unit->hci_cmdwait)) {
-		IF_DEQUEUE(&unit->hci_cmdwait, m);
-		hci_output_cmd(unit, m);
-	}
-}
-
-/*
- * Command Complete
- *
- * Update our record of num_cmd_pkts then handle the completed command,
- * and optionally restart cmd output on the unit.
- */
-static void
-hci_event_command_compl(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_command_compl_ep ep;
-	hci_status_rp rp;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	DPRINTFN(1, "(%s) opcode (%03x|%04x) num_cmd_pkts = %d\n",
-		device_get_nameunit(unit->hci_dev),
-		HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)),
-		ep.num_cmd_pkts);
-
-	/*
-	 * I am not sure if this is completely correct, it is not guaranteed
-	 * that a command_complete packet will contain the status though most
-	 * do seem to.
-	 */
-	m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
-	if (rp.status > 0)
-		kprintf("%s: CommandComplete opcode (%03x|%04x) failed (status=0x%02x)\n",
-		    device_get_nameunit(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)),
-		    HCI_OCF(letoh16(ep.opcode)), rp.status);
-
-	unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
-
-	/*
-	 * post processing of completed commands
-	 */
-	switch(letoh16(ep.opcode)) {
-	case HCI_CMD_READ_BDADDR:
-		hci_cmd_read_bdaddr(unit, m);
-		break;
-
-	case HCI_CMD_READ_BUFFER_SIZE:
-		hci_cmd_read_buffer_size(unit, m);
-		break;
-
-	case HCI_CMD_READ_LOCAL_FEATURES:
-		hci_cmd_read_local_features(unit, m);
-		break;
-
-	case HCI_CMD_READ_LOCAL_VER:
-		hci_cmd_read_local_ver(unit, m);
-		break;
-
-	case HCI_CMD_READ_LOCAL_COMMANDS:
-		hci_cmd_read_local_commands(unit, m);
-		break;
-
-	case HCI_CMD_RESET:
-		hci_cmd_reset(unit, m);
-		break;
-
-	default:
-		break;
-	}
-
-	while (unit->hci_num_cmd_pkts > 0 && !IF_QEMPTY(&unit->hci_cmdwait)) {
-		IF_DEQUEUE(&unit->hci_cmdwait, m);
-		hci_output_cmd(unit, m);
-	}
-}
-
-/*
- * Number of Completed Packets
- *
- * This is sent periodically by the Controller telling us how many
- * buffers are now freed up and which handle was using them. From
- * this we determine which type of buffer it was and add the qty
- * back into the relevant packet counter, then restart output on
- * links that have halted.
- */
-static void
-hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_num_compl_pkts_ep ep;
-	struct hci_link *link, *next;
-	uint16_t handle, num;
-	int num_acl = 0, num_sco = 0;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	while (ep.num_con_handles--) {
-		m_copydata(m, 0, sizeof(handle), (caddr_t)&handle);
-		m_adj(m, sizeof(handle));
-		handle = letoh16(handle);
-
-		m_copydata(m, 0, sizeof(num), (caddr_t)&num);
-		m_adj(m, sizeof(num));
-		num = letoh16(num);
-
-		link = hci_link_lookup_handle(unit, handle);
-		if (link) {
-			if (link->hl_type == HCI_LINK_ACL) {
-				num_acl += num;
-				hci_acl_complete(link, num);
-			} else {
-				num_sco += num;
-				hci_sco_complete(link, num);
-			}
-		} else {
-			/* XXX need to issue Read_Buffer_Size or Reset? */
-			kprintf("%s: unknown handle %d! "
-			    "(losing track of %d packet buffer%s)\n",
-			    device_get_nameunit(unit->hci_dev), handle,
-			    num, (num == 1 ? "" : "s"));
-		}
-	}
-
-	/*
-	 * Move up any queued packets. When a link has sent data, it will move
-	 * to the back of the queue - technically then if a link had something
-	 * to send and there were still buffers available it could get started
-	 * twice but it seemed more important to to handle higher loads fairly
-	 * than worry about wasting cycles when we are not busy.
-	 */
-
-	unit->hci_num_acl_pkts += num_acl;
-	unit->hci_num_sco_pkts += num_sco;
-
-	link = TAILQ_FIRST(&unit->hci_links);
-	while (link && (unit->hci_num_acl_pkts > 0 || unit->hci_num_sco_pkts > 0)) {
-		next = TAILQ_NEXT(link, hl_next);
-
-		if (link->hl_type == HCI_LINK_ACL) {
-			if (unit->hci_num_acl_pkts > 0 && link->hl_txqlen > 0)
-				hci_acl_start(link);
-		} else {
-			if (unit->hci_num_sco_pkts > 0 && link->hl_txqlen > 0)
-				hci_sco_start(link);
-		}
-
-		link = next;
-	}
-}
-
-/*
- * Inquiry Result
- *
- * keep a note of devices seen, so we know which unit to use
- * on outgoing connections
- */
-static void
-hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_inquiry_result_ep ep;
-	hci_inquiry_response ir;
-	struct hci_memo *memo;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	DPRINTFN(1, "(%s) %d response%s\n", device_get_nameunit(unit->hci_dev),
-	    ep.num_responses, (ep.num_responses == 1 ? "" : "s"));
-
-	while(ep.num_responses--) {
-		KKASSERT(m->m_pkthdr.len >= sizeof(ir));
-		m_copydata(m, 0, sizeof(ir), (caddr_t)&ir);
-		m_adj(m, sizeof(ir));
-
-		DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
-			ir.bdaddr.b[5], ir.bdaddr.b[4], ir.bdaddr.b[3],
-			ir.bdaddr.b[2], ir.bdaddr.b[1], ir.bdaddr.b[0]);
-
-		memo = hci_memo_new(unit, &ir.bdaddr);
-		if (memo != NULL) {
-			memo->page_scan_rep_mode = ir.page_scan_rep_mode;
-			memo->page_scan_mode = ir.page_scan_mode;
-			memo->clock_offset = ir.clock_offset;
-		}
-	}
-}
-
-/*
- * Inquiry Result with RSSI
- *
- * as above but different packet when RSSI result is enabled
- */
-static void
-hci_event_rssi_result(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_rssi_result_ep ep;
-	hci_rssi_response rr;
-	struct hci_memo *memo;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	DPRINTFN(1, "%d response%s\n", ep.num_responses,
-				(ep.num_responses == 1 ? "" : "s"));
-
-	while(ep.num_responses--) {
-		KKASSERT(m->m_pkthdr.len >= sizeof(rr));
-		m_copydata(m, 0, sizeof(rr), (caddr_t)&rr);
-		m_adj(m, sizeof(rr));
-
-		DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
-			rr.bdaddr.b[5], rr.bdaddr.b[4], rr.bdaddr.b[3],
-			rr.bdaddr.b[2], rr.bdaddr.b[1], rr.bdaddr.b[0]);
-
-		memo = hci_memo_new(unit, &rr.bdaddr);
-		if (memo != NULL) {
-			memo->page_scan_rep_mode = rr.page_scan_rep_mode;
-			memo->page_scan_mode = 0;
-			memo->clock_offset = rr.clock_offset;
-		}
-	}
-}
-
-/*
- * Connection Complete
- *
- * Sent to us when a connection is made. If there is no link
- * structure already allocated for this, we must have changed
- * our mind, so just disconnect.
- */
-static void
-hci_event_con_compl(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_con_compl_ep ep;
-	hci_write_link_policy_settings_cp cp;
-	struct hci_link *link;
-	int err;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	DPRINTFN(1, "(%s) %s connection complete for "
-		"%02x:%02x:%02x:%02x:%02x:%02x status %#x\n",
-		device_get_nameunit(unit->hci_dev),
-		(ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"),
-		ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
-		ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
-		ep.status);
-
-	link = hci_link_lookup_bdaddr(unit, &ep.bdaddr, ep.link_type);
-
-	if (ep.status) {
-		if (link != NULL) {
-			switch (ep.status) {
-			case 0x04: /* "Page Timeout" */
-				err = EHOSTDOWN;
-				break;
-
-			case 0x08: /* "Connection Timed Out" */
-			case 0x10: /* "Connection Accept Timeout Exceeded" */
-				err = ETIMEDOUT;
-				break;
-
-			case 0x16: /* "Connection Terminated by Local Host" */
-				err = 0;
-				break;
-
-			default:
-				err = ECONNREFUSED;
-				break;
-			}
-
-			hci_link_free(link, err);
-		}
-
-		return;
-	}
-
-	if (link == NULL) {
-		hci_discon_cp dp;
-
-		dp.con_handle = ep.con_handle;
-		dp.reason = 0x13; /* "Remote User Terminated Connection" */
-
-		hci_send_cmd(unit, HCI_CMD_DISCONNECT, &dp, sizeof(dp));
-		return;
-	}
-
-	/* XXX could check auth_enable here */
-
-	if (ep.encryption_mode)
-		link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
-
-	link->hl_state = HCI_LINK_OPEN;
-	link->hl_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
-
-	if (ep.link_type == HCI_LINK_ACL) {
-		cp.con_handle = ep.con_handle;
-		cp.settings = htole16(unit->hci_link_policy);
-		err = hci_send_cmd(unit, HCI_CMD_WRITE_LINK_POLICY_SETTINGS,
-						&cp, sizeof(cp));
-		if (err)
-			kprintf("%s: Warning, could not write link policy\n",
-			    device_get_nameunit(unit->hci_dev));
-
-		err = hci_send_cmd(unit, HCI_CMD_READ_CLOCK_OFFSET,
-				    &cp.con_handle, sizeof(cp.con_handle));
-		if (err)
-			kprintf("%s: Warning, could not read clock offset\n",
-			    device_get_nameunit(unit->hci_dev));
- 
-		err = hci_acl_setmode(link);
-		if (err == EINPROGRESS)
-			return;
-
-		hci_acl_linkmode(link);
-	} else {
-		(*link->hl_sco->sp_proto->connected)(link->hl_sco->sp_upper);
-	}
-}
-
-/*
- * Disconnection Complete
- *
- * This is sent in response to a disconnection request, but also if
- * the remote device goes out of range.
- */
-static void
-hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_discon_compl_ep ep;
-	struct hci_link *link;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	ep.con_handle = letoh16(ep.con_handle);
-
-	DPRINTFN(1, "(%s) handle #%d, status=0x%x\n",
-	    device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status);
-
-	link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle));
-	if (link)
-		hci_link_free(link, ENOENT); /* XXX NetBSD used ENOLINK here */
-}
-
-/*
- * Connect Request
- *
- * We check upstream for appropriate listeners and accept connections
- * that are wanted.
- */
-static void
-hci_event_con_req(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_con_req_ep ep;
-	hci_accept_con_cp ap;
-	hci_reject_con_cp rp;
-	struct hci_link *link;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	DPRINTFN(1, "(%s) bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
-		"class %2.2x%2.2x%2.2x type %s\n",
-	    device_get_nameunit(unit->hci_dev),
-	    ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
-	    ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
-	    ep.uclass[0], ep.uclass[1], ep.uclass[2],
-	    ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO");
-
-	if (ep.link_type == HCI_LINK_ACL)
-		link = hci_acl_newconn(unit, &ep.bdaddr);
-	else
-		link = hci_sco_newconn(unit, &ep.bdaddr);
-
-	if (link == NULL) {
-		memset(&rp, 0, sizeof(rp));
-		bdaddr_copy(&rp.bdaddr, &ep.bdaddr);
-		rp.reason = 0x0f;	/* Unacceptable BD_ADDR */
-
-		hci_send_cmd(unit, HCI_CMD_REJECT_CON, &rp, sizeof(rp));
-	} else {
-		memset(&ap, 0, sizeof(ap));
-		bdaddr_copy(&ap.bdaddr, &ep.bdaddr);
-		if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH)
-			ap.role = HCI_ROLE_MASTER;
-		else
-			ap.role = HCI_ROLE_SLAVE;
-
-		hci_send_cmd(unit, HCI_CMD_ACCEPT_CON, &ap, sizeof(ap));
-	}
-}
-
-/*
- * Auth Complete
- *
- * Authentication has been completed on an ACL link. We can notify the
- * upper layer protocols unless further mode changes are pending.
- */
-static void
-hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_auth_compl_ep ep;
-	struct hci_link *link;
-	int err;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
-
-	DPRINTFN(1, "(%s) handle #%d, status=0x%x\n",
-	    device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status);
-
-	link = hci_link_lookup_handle(unit, ep.con_handle);
-	if (link == NULL || link->hl_type != HCI_LINK_ACL)
-		return;
-
-	if (ep.status == 0) {
-		link->hl_flags |= HCI_LINK_AUTH;
-
-		if (link->hl_state == HCI_LINK_WAIT_AUTH)
-			link->hl_state = HCI_LINK_OPEN;
-
-		err = hci_acl_setmode(link);
-		if (err == EINPROGRESS)
-			return;
-	}
-
-	hci_acl_linkmode(link);
-}
-
-/*
- * Encryption Change
- *
- * The encryption status has changed. Basically, we note the change
- * then notify the upper layer protocol unless further mode changes
- * are pending.
- * Note that if encryption gets disabled when it has been requested,
- * we will attempt to enable it again.. (its a feature not a bug :)
- */
-static void
-hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_encryption_change_ep ep;
-	struct hci_link *link;
-	int err;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
-
-	DPRINTFN(1, "(%s) handle #%d, status=0x%x, encryption_enable=0x%x\n",
-	    device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status,
-	    ep.encryption_enable);
-
-	link = hci_link_lookup_handle(unit, ep.con_handle);
-	if (link == NULL || link->hl_type != HCI_LINK_ACL)
-		return;
-
-	if (ep.status == 0) {
-		if (ep.encryption_enable == 0)
-			link->hl_flags &= ~HCI_LINK_ENCRYPT;
-		else
-			link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
-
-		if (link->hl_state == HCI_LINK_WAIT_ENCRYPT)
-			link->hl_state = HCI_LINK_OPEN;
-
-		err = hci_acl_setmode(link);
-		if (err == EINPROGRESS)
-			return;
-	}
-
-	hci_acl_linkmode(link);
-}
-
-/*
- * Change Connection Link Key Complete
- *
- * Link keys are handled in userland but if we are waiting to secure
- * this link, we should notify the upper protocols. A SECURE request
- * only needs a single key change, so we can cancel the request.
- */
-static void
-hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_change_con_link_key_compl_ep ep;
-	struct hci_link *link;
-	int err;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
-
-	DPRINTFN(1, "(%s) handle #%d, status=0x%x\n",
-	    device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status);
-
-	link = hci_link_lookup_handle(unit, ep.con_handle);
-	if (link == NULL || link->hl_type != HCI_LINK_ACL)
-		return;
-
-	link->hl_flags &= ~HCI_LINK_SECURE_REQ;
-
-	if (ep.status == 0) {
-		link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_SECURE);
-
-		if (link->hl_state == HCI_LINK_WAIT_SECURE)
-			link->hl_state = HCI_LINK_OPEN;
-
-		err = hci_acl_setmode(link);
-		if (err == EINPROGRESS)
-			return;
-	}
-
-	hci_acl_linkmode(link);
-}
-
-/*
- * Read Clock Offset Complete
- *
- * We keep a note of the clock offset of remote devices when a
- * link is made, in order to facilitate reconnections to the device
- */
-static void
-hci_event_read_clock_offset_compl(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_read_clock_offset_compl_ep ep;
-	struct hci_link *link;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
-	m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
-	m_adj(m, sizeof(ep));
-
-	DPRINTFN(1, "handle #%d, offset=%u, status=0x%x\n",
-	    letoh16(ep.con_handle), letoh16(ep.clock_offset), ep.status);
-
-	ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
-	link = hci_link_lookup_handle(unit, ep.con_handle);
-
-	if (ep.status != 0 || link == NULL)
-		return;
-
-	link->hl_clock = ep.clock_offset;
-}
-
-/*
- * process results of read_bdaddr command_complete event
- */
-static void
-hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_read_bdaddr_rp rp;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
-	m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
-	m_adj(m, sizeof(rp));
-
-	if (rp.status > 0)
-		return;
-
-	if ((unit->hci_flags & BTF_INIT_BDADDR) == 0)
-		return;
-
-	bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr);
-
-	unit->hci_flags &= ~BTF_INIT_BDADDR;
-
-	wakeup(unit);
-}
-
-/*
- * process results of read_buffer_size command_complete event
- */
-static void
-hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_read_buffer_size_rp rp;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
-	m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
-	m_adj(m, sizeof(rp));
-
-	if (rp.status > 0)
-		return;
-
-	if ((unit->hci_flags & BTF_INIT_BUFFER_SIZE) == 0)
-		return;
-
-	unit->hci_max_acl_size = letoh16(rp.max_acl_size);
-	unit->hci_num_acl_pkts = letoh16(rp.num_acl_pkts);
-	unit->hci_max_sco_size = rp.max_sco_size;
-	unit->hci_num_sco_pkts = letoh16(rp.num_sco_pkts);
-
-	unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE;
-
-	wakeup(unit);
-}
-
-/*
- * process results of read_local_features command_complete event
- */
-static void
-hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_read_local_features_rp rp;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
-	m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
-	m_adj(m, sizeof(rp));
-
-	if (rp.status > 0)
-		return;
-
-	if ((unit->hci_flags & BTF_INIT_FEATURES) == 0)
-		return;
-
-	unit->hci_lmp_mask = 0;
-
-	if (rp.features[0] & HCI_LMP_ROLE_SWITCH)
-		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
-
-	if (rp.features[0] & HCI_LMP_HOLD_MODE)
-		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_HOLD_MODE;
-
-	if (rp.features[0] & HCI_LMP_SNIFF_MODE)
-		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
-
-	if (rp.features[1] & HCI_LMP_PARK_MODE)
-		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_PARK_MODE;
-
-	/* ACL packet mask */
-	unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
-
-	if (rp.features[0] & HCI_LMP_3SLOT)
-		unit->hci_acl_mask |= HCI_PKT_DM3 | HCI_PKT_DH3;
-
-	if (rp.features[0] & HCI_LMP_5SLOT)
-		unit->hci_acl_mask |= HCI_PKT_DM5 | HCI_PKT_DH5;
-
-	if ((rp.features[3] & HCI_LMP_EDR_ACL_2MBPS) == 0)
-		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH1
-				    | HCI_PKT_2MBPS_DH3
-				    | HCI_PKT_2MBPS_DH5;
-
-	if ((rp.features[3] & HCI_LMP_EDR_ACL_3MBPS) == 0)
-		unit->hci_acl_mask |= HCI_PKT_3MBPS_DH1
-				    | HCI_PKT_3MBPS_DH3
-				    | HCI_PKT_3MBPS_DH5;
-
-	if ((rp.features[4] & HCI_LMP_3SLOT_EDR_ACL) == 0)
-		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH3
-				    | HCI_PKT_3MBPS_DH3;
-
-	if ((rp.features[5] & HCI_LMP_5SLOT_EDR_ACL) == 0)
-		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH5
-				    | HCI_PKT_3MBPS_DH5;
-
-	unit->hci_packet_type = unit->hci_acl_mask;
-
-	/* SCO packet mask */
-	unit->hci_sco_mask = 0;
-	if (rp.features[1] & HCI_LMP_SCO_LINK)
-		unit->hci_sco_mask |= HCI_PKT_HV1;
-
-	if (rp.features[1] & HCI_LMP_HV2_PKT)
-		unit->hci_sco_mask |= HCI_PKT_HV2;
-
-	if (rp.features[1] & HCI_LMP_HV3_PKT)
-		unit->hci_sco_mask |= HCI_PKT_HV3;
-
-	if (rp.features[3] & HCI_LMP_EV3_PKT)
-		unit->hci_sco_mask |= HCI_PKT_EV3;
-
-	if (rp.features[4] & HCI_LMP_EV4_PKT)
-		unit->hci_sco_mask |= HCI_PKT_EV4;
-
-	if (rp.features[4] & HCI_LMP_EV5_PKT)
-		unit->hci_sco_mask |= HCI_PKT_EV5;
-
-	/* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */
-
-	unit->hci_flags &= ~BTF_INIT_FEATURES;
-
-	wakeup(unit);
-
-	DPRINTFN(1, "%s: lmp_mask %4.4x, acl_mask %4.4x, sco_mask %4.4x\n",
-		device_get_nameunit(unit->hci_dev), unit->hci_lmp_mask,
-		unit->hci_acl_mask, unit->hci_sco_mask);
-}
-
-/*
- * process results of read_local_ver command_complete event
- *
- * reading local supported commands is only supported from 1.2 spec
- */
-static void
-hci_cmd_read_local_ver(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_read_local_ver_rp rp;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
-	m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
-	m_adj(m, sizeof(rp));
-
-	if (rp.status != 0)
-		return;
-
-	if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0)
-		return;
-
-	if (rp.hci_version < HCI_SPEC_V12) {
-		unit->hci_flags &= ~BTF_INIT_COMMANDS;
-		wakeup(unit);
-		return;
-	}
-
-	hci_send_cmd(unit, HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0);
-}
-
-/*
- * process results of read_local_commands command_complete event
- */
-static void
-hci_cmd_read_local_commands(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_read_local_commands_rp rp;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
-	m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
-	m_adj(m, sizeof(rp));
-
-	if (rp.status != 0)
-		return;
-
-	if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0)
-		return;
-
-	unit->hci_flags &= ~BTF_INIT_COMMANDS;
-	memcpy(unit->hci_cmds, rp.commands, HCI_COMMANDS_SIZE);
-
-	wakeup(unit);
-}
-
-/*
- * process results of reset command_complete event
- *
- * This has killed all the connections, so close down anything we have left,
- * and reinitialise the unit.
- */
-static void
-hci_cmd_reset(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_reset_rp rp;
-	struct hci_link *link, *next;
-	int acl;
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
-	m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
-	m_adj(m, sizeof(rp));
-
-	if (rp.status != 0)
-		return;
-
-	/*
-	 * release SCO links first, since they may be holding
-	 * an ACL link reference.
-	 */
-	for (acl = 0 ; acl < 2 ; acl++) {
-		next = TAILQ_FIRST(&unit->hci_links);
-		while ((link = next) != NULL) {
-			next = TAILQ_NEXT(link, hl_next);
-			if (acl || link->hl_type != HCI_LINK_ACL)
-				hci_link_free(link, ECONNABORTED);
-		}
-	}
-
-	unit->hci_num_acl_pkts = 0;
-	unit->hci_num_sco_pkts = 0;
-
-	if (hci_send_cmd(unit, HCI_CMD_READ_BDADDR, NULL, 0))
-		return;
-
-	if (hci_send_cmd(unit, HCI_CMD_READ_BUFFER_SIZE, NULL, 0))
-		return;
-
-	if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0))
-		return;
-
-	if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_VER, NULL, 0))
-		return;
-}
diff --git a/sys/netbt/hci_ioctl.c b/sys/netbt/hci_ioctl.c
deleted file mode 100644
index 94d7a489ec..0000000000
--- a/sys/netbt/hci_ioctl.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/* $OpenBSD: src/sys/netbt/hci_ioctl.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: hci_ioctl.c,v 1.7 2007/11/28 20:16:12 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/domain.h>
-#include <sys/kernel.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/priv.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-#include <netbt/rfcomm.h>
-
-#ifdef BLUETOOTH_DEBUG
-#define BDADDR(bd)	(bd).b[5], (bd).b[4], (bd).b[3],	\
-			(bd).b[2], (bd).b[1], (bd).b[0]
-
-static void
-hci_dump(void)
-{
-	struct hci_unit *unit;
-	struct hci_link *link;
-	struct l2cap_channel *chan;
-	struct rfcomm_session *rs;
-	struct rfcomm_dlc *dlc;
-
-	kprintf("HCI:\n");
-	TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
-		kprintf("UNIT %s: flags 0x%4.4x, "
-			"num_cmd=%d, num_acl=%d, num_sco=%d\n",
-			device_get_nameunit(unit->hci_dev), unit->hci_flags,
-			unit->hci_num_cmd_pkts,
-			unit->hci_num_acl_pkts,
-			unit->hci_num_sco_pkts);
-		TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
-			kprintf("+HANDLE #%d: %s "
-			    "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
-			    "state %d, refcnt %d\n",
-			    link->hl_handle,
-			    (link->hl_type == HCI_LINK_ACL ? "ACL":"SCO"),
-			    BDADDR(link->hl_bdaddr),
-			    link->hl_state, link->hl_refcnt);
-		}
-	}
-
-	kprintf("L2CAP:\n");
-	LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
-		kprintf("CID #%d state %d, psm=0x%4.4x, "
-		    "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
-		    "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
-		    chan->lc_lcid, chan->lc_state, chan->lc_raddr.bt_psm,
-		    BDADDR(chan->lc_laddr.bt_bdaddr),
-		    BDADDR(chan->lc_raddr.bt_bdaddr));
-	}
-
-	LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) {
-		kprintf("LISTEN psm=0x%4.4x, "
-		    "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
-		    chan->lc_laddr.bt_psm,
-		    BDADDR(chan->lc_laddr.bt_bdaddr));
-	}
-
-	kprintf("RFCOMM:\n");
-	LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
-		chan = rs->rs_l2cap;
-		kprintf("SESSION: state=%d, flags=0x%4.4x, psm 0x%4.4x "
-		    "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
-		    "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
-		    rs->rs_state, rs->rs_flags, chan->lc_raddr.bt_psm,
-		    BDADDR(chan->lc_laddr.bt_bdaddr),
-		    BDADDR(chan->lc_raddr.bt_bdaddr));
-		LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
-			kprintf("+DLC channel=%d, dlci=%d, "
-			    "state=%d, flags=0x%4.4x, rxcred=%d, rxsize=%ld, "
-			    "txcred=%d, pending=%d, txqlen=%d\n",
-			    dlc->rd_raddr.bt_channel, dlc->rd_dlci,
-			    dlc->rd_state, dlc->rd_flags,
-			    dlc->rd_rxcred, (unsigned long)dlc->rd_rxsize,
-			    dlc->rd_txcred, dlc->rd_pending,
-			    (dlc->rd_txbuf ? dlc->rd_txbuf->m_pkthdr.len : 0));
-		}
-	}
-
-	LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
-		chan = rs->rs_l2cap;
-		kprintf("LISTEN: psm 0x%4.4x, "
-		    "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
-		    chan->lc_laddr.bt_psm,
-		    BDADDR(chan->lc_laddr.bt_bdaddr));
-		LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next)
-			kprintf("+DLC channel=%d\n", dlc->rd_laddr.bt_channel);
-	}
-}
-
-#undef BDADDR
-#endif
-
-int
-hci_ioctl(unsigned long cmd, void *data, struct proc *p)
-{
-	struct btreq *btr = data;
-	struct thread *td = curthread; 
-	struct hci_unit *unit;
-	int err = 0;
-
-	DPRINTFN(1, "cmd %#lx\n", cmd);
-
-	switch(cmd) {
-#ifdef BLUETOOTH_DEBUG
-	case SIOCBTDUMP:
-		hci_dump();
-		return 0;
-#endif
-	/*
-	 * Get unit info based on address rather than name
-	 */
-	case SIOCGBTINFOA:
-		unit = hci_unit_lookup(&btr->btr_bdaddr);
-		if (unit == NULL)
-			return ENXIO;
-
-		break;
-
-	/*
-	 * The remaining ioctl's all use the same btreq structure and
-	 * index on the name of the device, so we look that up first.
-	 */
-	case SIOCNBTINFO:
-		/* empty name means give the first unit */
-		if (btr->btr_name[0] == '\0') {
-			unit = NULL;
-			break;
-		}
-
-		/* else fall through and look it up */
-	case SIOCGBTINFO:
-	case SIOCSBTFLAGS:
-	case SIOCSBTPOLICY:
-	case SIOCSBTPTYPE:
-	case SIOCGBTSTATS:
-	case SIOCZBTSTATS:
-	case SIOCSBTSCOMTU:
-		TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
-			if (strncmp(device_get_nameunit(unit->hci_dev),
-			    btr->btr_name, HCI_DEVNAME_SIZE) == 0)
-				break;
-		}
-
-		if (unit == NULL)
-			return ENXIO;
-
-		break;
-
-	default:	/* not one of mine */
-		return EPASSTHROUGH;
-	}
-
-	switch(cmd) {
-	case SIOCNBTINFO:	/* get next info */
-		if (unit)
-			unit = TAILQ_NEXT(unit, hci_next);
-		else
-			unit = TAILQ_FIRST(&hci_unit_list);
-
-		if (unit == NULL) {
-			err = ENXIO;
-			break;
-		}
-
-		/* and fall through to */
-	case SIOCGBTINFO:	/* get unit info */
-	case SIOCGBTINFOA:	/* get info by address */
-		memset(btr, 0, sizeof(struct btreq));
-		strlcpy(btr->btr_name, device_get_nameunit(unit->hci_dev),
-		    HCI_DEVNAME_SIZE);
-		bdaddr_copy(&btr->btr_bdaddr, &unit->hci_bdaddr);
-
-		btr->btr_flags = unit->hci_flags;
-
-		btr->btr_num_cmd = unit->hci_num_cmd_pkts;
-		btr->btr_num_acl = unit->hci_num_acl_pkts;
-		btr->btr_num_sco = unit->hci_num_sco_pkts;
-		btr->btr_acl_mtu = unit->hci_max_acl_size;
-		btr->btr_sco_mtu = unit->hci_max_sco_size;
-
-		btr->btr_packet_type = unit->hci_packet_type;
-		btr->btr_link_policy = unit->hci_link_policy;
-		break;
-
-	case SIOCSBTFLAGS:	/* set unit flags (privileged) */
-		err = priv_check(td, PRIV_ROOT);
-		if (err)
-			break;
-
-		if ((unit->hci_flags & BTF_UP)
-		    && (btr->btr_flags & BTF_UP) == 0) {
-			hci_disable(unit);
-			unit->hci_flags &= ~BTF_UP;
-		}
-
-		unit->hci_flags |= (btr->btr_flags & BTF_INIT);
-
-		if ((unit->hci_flags & BTF_UP) == 0
-		    && (btr->btr_flags & BTF_UP)) {
-			err = hci_enable(unit);
-			if (err)
-				break;
-
-			unit->hci_flags |= BTF_UP;
-		}
-
-		btr->btr_flags = unit->hci_flags;
-		break;
-
-	case SIOCSBTPOLICY:	/* set unit link policy (privileged) */
-		err = priv_check(td, PRIV_ROOT);
-		if (err)
-			break;
-
-		unit->hci_link_policy = btr->btr_link_policy;
-		unit->hci_link_policy &= unit->hci_lmp_mask;
-		btr->btr_link_policy = unit->hci_link_policy;
-		break;
-
-	case SIOCSBTPTYPE:	/* set unit packet types (privileged) */
-		err = priv_check(td, PRIV_ROOT);
-		if (err)
-			break;
-
-		unit->hci_packet_type = btr->btr_packet_type;
-		unit->hci_packet_type &= unit->hci_acl_mask;
-		btr->btr_packet_type = unit->hci_packet_type;
-		break;
-
-	case SIOCGBTSTATS:	/* get unit statistics */
-		(*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 0);
-		break;
-
-	case SIOCZBTSTATS:	/* get & reset unit statistics */
-		err = priv_check(td, PRIV_ROOT);
-		if (err)
-			break;
-
-		(*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 1);
-		break;
-
-	case SIOCSBTSCOMTU:	/* set sco_mtu value for unit */
-		/*
-		 * This is a temporary ioctl and may not be supported
-		 * in the future. The need is that if SCO packets are
-		 * sent to USB bluetooth controllers that are not an
-		 * integer number of frame sizes, the USB bus locks up.
-		 */
-		err = priv_check(td, PRIV_ROOT);
-		if (err)
-			break;
-
-		unit->hci_max_sco_size = btr->btr_sco_mtu;
-		break;
-
-	default:
-		err = EFAULT;
-		break;
-	}
-
-	return err;
-}
diff --git a/sys/netbt/hci_link.c b/sys/netbt/hci_link.c
deleted file mode 100644
index d85981f176..0000000000
--- a/sys/netbt/hci_link.c
+++ /dev/null
@@ -1,1083 +0,0 @@
-/* $OpenBSD: src/sys/netbt/hci_link.c,v 1.7 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: hci_link.c,v 1.16 2007/11/10 23:12:22 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/queue.h>
-#include <sys/systm.h>
-#include <sys/endian.h>
-#include <sys/callout.h>
-#include <net/if.h>
-#include <sys/bus.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-#include <netbt/sco.h>
-
-/*******************************************************************************
- *
- *	HCI ACL Connections
- */
-
-/*
- * Automatically expire unused ACL connections after this number of
- * seconds (if zero, do not expire unused connections) [sysctl]
- */
-int hci_acl_expiry = 10;	/* seconds */
-
-/*
- * hci_acl_open(unit, bdaddr)
- *
- * open ACL connection to remote bdaddr. Only one ACL connection is permitted
- * between any two Bluetooth devices, so we look for an existing one before
- * trying to start a new one.
- */
-struct hci_link *
-hci_acl_open(struct hci_unit *unit, bdaddr_t *bdaddr)
-{
-	struct hci_link *link;
-	struct hci_memo *memo;
-	hci_create_con_cp cp;
-	int err;
-
-	KKASSERT(unit != NULL);
-	KKASSERT(bdaddr != NULL);
-
-	link = hci_link_lookup_bdaddr(unit, bdaddr, HCI_LINK_ACL);
-	if (link == NULL) {
-		link = hci_link_alloc(unit);
-		if (link == NULL)
-			return NULL;
-
-		link->hl_type = HCI_LINK_ACL;
-		bdaddr_copy(&link->hl_bdaddr, bdaddr);
-	}
-
-	switch(link->hl_state) {
-	case HCI_LINK_CLOSED:
-		/*
-		 * open connection to remote device
-		 */
-		memset(&cp, 0, sizeof(cp));
-		bdaddr_copy(&cp.bdaddr, bdaddr);
-		cp.pkt_type = htole16(unit->hci_packet_type);
-
-		memo = hci_memo_find(unit, bdaddr);
-		if (memo != NULL) {
-			cp.page_scan_rep_mode = memo->page_scan_rep_mode;
-			cp.page_scan_mode = memo->page_scan_mode;
-			cp.clock_offset = memo->clock_offset;
-		}
-
-		if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH)
-			cp.accept_role_switch = 1;
-
-		err = hci_send_cmd(unit, HCI_CMD_CREATE_CON, &cp, sizeof(cp));
-		if (err) {
-			hci_link_free(link, err);
-			return NULL;
-		}
-
-		link->hl_state = HCI_LINK_WAIT_CONNECT;
-		break;
-
-	case HCI_LINK_WAIT_CONNECT:
-	case HCI_LINK_WAIT_AUTH:
-	case HCI_LINK_WAIT_ENCRYPT:
-	case HCI_LINK_WAIT_SECURE:
-		/*
-		 * somebody else already trying to connect, we just
-		 * sit on the bench with them..
-		 */
-		break;
-
-	case HCI_LINK_OPEN:
-		/*
-		 * If already open, halt any expiry callouts. We dont need
-		 * to care about already invoking callouts since refcnt >0
-		 * will keep the link alive.
-		 */
-		callout_stop(&link->hl_expire);
-		break;
-
-	default:
-		UNKNOWN(link->hl_state);
-		return NULL;
-	}
-
-	/* open */
-	link->hl_refcnt++;
-
-	return link;
-}
-
-/*
- * Close ACL connection. When there are no more references to this link,
- * we can either close it down or schedule a delayed closedown.
- */
-void
-hci_acl_close(struct hci_link *link, int err)
-{
-	KKASSERT(link != NULL);
-
-	if (--link->hl_refcnt == 0) {
-		if (link->hl_state == HCI_LINK_CLOSED)
-			hci_link_free(link, err);
-		else if (hci_acl_expiry > 0)
-			callout_reset(&link->hl_expire, hci_acl_expiry * hz,
-			    hci_acl_timeout, link);
-	}
-}
-
-/*
- * Incoming ACL connection.
- *
- * For now, we accept all connections but it would be better to check
- * the L2CAP listen list and only accept when there is a listener
- * available.
- *
- * There should not be a link to the same bdaddr already, we check
- * anyway though its left unhandled for now.
- */
-struct hci_link *
-hci_acl_newconn(struct hci_unit *unit, bdaddr_t *bdaddr)
-{
-	struct hci_link *link;
-
-	link = hci_link_lookup_bdaddr(unit, bdaddr, HCI_LINK_ACL);
-	if (link != NULL)
-		return NULL;
-
-	link = hci_link_alloc(unit);
-	if (link != NULL) {
-		link->hl_state = HCI_LINK_WAIT_CONNECT;
-		link->hl_type = HCI_LINK_ACL;
-		bdaddr_copy(&link->hl_bdaddr, bdaddr);
-
-		if (hci_acl_expiry > 0)
-			callout_reset(&link->hl_expire, hci_acl_expiry * hz,
-			    hci_acl_timeout, link);
-	}
-
-	return link;
-}
-
-void
-hci_acl_timeout(void *arg)
-{
-	struct hci_link *link = arg;
-	hci_discon_cp cp;
-	int err;
-
-	crit_enter();
-
-	if (link->hl_refcnt > 0) 
-		goto out;
-
-	DPRINTF("link #%d expired\n", link->hl_handle);
-
-	switch (link->hl_state) {
-	case HCI_LINK_CLOSED:
-	case HCI_LINK_WAIT_CONNECT:
-		hci_link_free(link, ECONNRESET);
-		break;
-
-	case HCI_LINK_WAIT_AUTH:
-	case HCI_LINK_WAIT_ENCRYPT:
-	case HCI_LINK_WAIT_SECURE:
-	case HCI_LINK_OPEN:
-		cp.con_handle = htole16(link->hl_handle);
-		cp.reason = 0x13; /* "Remote User Terminated Connection" */
-
-		err = hci_send_cmd(link->hl_unit, HCI_CMD_DISCONNECT,
-					&cp, sizeof(cp));
-
-		if (err) {
-			DPRINTF("error %d sending HCI_CMD_DISCONNECT\n",
-			    err);
-		}
-
-		break;
-
-	default:
-		UNKNOWN(link->hl_state);
-		break;
-	}
-
-out:
-	crit_exit(); 
-}
-
-/*
- * Initiate any Link Mode change requests.
- */
-int
-hci_acl_setmode(struct hci_link *link)
-{
-	int err;
-
-	KKASSERT(link != NULL);
-	KKASSERT(link->hl_unit != NULL);
-
-	if (link->hl_state != HCI_LINK_OPEN)
-		return EINPROGRESS;
-
-	if ((link->hl_flags & HCI_LINK_AUTH_REQ)
-	    && !(link->hl_flags & HCI_LINK_AUTH)) {
-		hci_auth_req_cp cp;
-
-		DPRINTF("(%s) requesting auth for handle #%d\n",
-		    device_get_nameunit(link->hl_unit->hci_dev),
-		    link->hl_handle);
-
-		link->hl_state = HCI_LINK_WAIT_AUTH;
-		cp.con_handle = htole16(link->hl_handle);
-		err = hci_send_cmd(link->hl_unit, HCI_CMD_AUTH_REQ,
-				   &cp, sizeof(cp));
-
-		return (err == 0 ? EINPROGRESS : err);
-	}
-
-	if ((link->hl_flags & HCI_LINK_ENCRYPT_REQ)
-	    && !(link->hl_flags & HCI_LINK_ENCRYPT)) {
-		hci_set_con_encryption_cp cp;
-
-		/* XXX we should check features for encryption capability */
-
-		DPRINTF("(%s) requesting encryption for handle #%d\n",
-		    device_get_nameunit(link->hl_unit->hci_dev),
-		    link->hl_handle);
-
-		link->hl_state = HCI_LINK_WAIT_ENCRYPT;
-		cp.con_handle = htole16(link->hl_handle);
-		cp.encryption_enable = 0x01;
-
-		err = hci_send_cmd(link->hl_unit, HCI_CMD_SET_CON_ENCRYPTION,
-				   &cp, sizeof(cp));
-
-		return (err == 0 ? EINPROGRESS : err);
-	}
-
-	if ((link->hl_flags & HCI_LINK_SECURE_REQ)) {
-		hci_change_con_link_key_cp cp;
-
-		/* always change link key for SECURE requests */
-		link->hl_flags &= ~HCI_LINK_SECURE;
-
-		DPRINTF("(%s) changing link key for handle #%d\n",
-		    device_get_nameunit(link->hl_unit->hci_dev),
-		    link->hl_handle);
-
-		link->hl_state = HCI_LINK_WAIT_SECURE;
-		cp.con_handle = htole16(link->hl_handle);
-
-		err = hci_send_cmd(link->hl_unit, HCI_CMD_CHANGE_CON_LINK_KEY,
-				   &cp, sizeof(cp));
-
-		return (err == 0 ? EINPROGRESS : err);
-	}
-
-	return 0;
-}
-
-/*
- * Link Mode changed.
- *
- * This is called from event handlers when the mode change
- * is complete. We notify upstream and restart the link.
- */
-void
-hci_acl_linkmode(struct hci_link *link)
-{
-	struct l2cap_channel *chan, *next;
-	int err, mode = 0;
-
-	DPRINTF("(%s) handle #%d, auth %s, encrypt %s, secure %s\n",
-	    device_get_nameunit(link->hl_unit->hci_dev), link->hl_handle,
-	    (link->hl_flags & HCI_LINK_AUTH ? "on" : "off"),
-	    (link->hl_flags & HCI_LINK_ENCRYPT ? "on" : "off"),
-	    (link->hl_flags & HCI_LINK_SECURE ? "on" : "off"));
-
-	if (link->hl_flags & HCI_LINK_AUTH)
-		mode |= L2CAP_LM_AUTH;
-
-	if (link->hl_flags & HCI_LINK_ENCRYPT)
-		mode |= L2CAP_LM_ENCRYPT;
-
-	if (link->hl_flags & HCI_LINK_SECURE)
-		mode |= L2CAP_LM_SECURE;
-
-	/*
-	 * The link state will only be OPEN here if the mode change
-	 * was successful. So, we can proceed with L2CAP connections,
-	 * or notify already establshed channels, to allow any that
-	 * are dissatisfied to disconnect before we restart.
-	 */
-	next = LIST_FIRST(&l2cap_active_list);
-	while ((chan = next) != NULL) {
-		next = LIST_NEXT(chan, lc_ncid);
-
-		if (chan->lc_link != link)
-			continue;
-
-		switch(chan->lc_state) {
-		case L2CAP_WAIT_SEND_CONNECT_REQ: /* we are connecting */
-			if ((mode & chan->lc_mode) != chan->lc_mode) {
-				l2cap_close(chan, ECONNABORTED);
-				break;
-			}
-
-			chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP;
-			err = l2cap_send_connect_req(chan);
-			if (err) {
-				l2cap_close(chan, err);
-				break;
-			}
-			break;
-
-		case L2CAP_WAIT_SEND_CONNECT_RSP: /* they are connecting */
-			if ((mode & chan->lc_mode) != chan->lc_mode) {
-				l2cap_send_connect_rsp(link, chan->lc_ident,
-							0, chan->lc_rcid,
-							L2CAP_SECURITY_BLOCK);
-
-				l2cap_close(chan, ECONNABORTED);
-				break;
-			}
-
-			l2cap_send_connect_rsp(link, chan->lc_ident,
-						chan->lc_lcid, chan->lc_rcid,
-						L2CAP_SUCCESS);
-
-			chan->lc_state = L2CAP_WAIT_CONFIG;
-			chan->lc_flags |= (L2CAP_WAIT_CONFIG_RSP | L2CAP_WAIT_CONFIG_REQ);
-			err = l2cap_send_config_req(chan);
-			if (err) {
-				l2cap_close(chan, err);
-				break;
-			}
-			break;
-
-		case L2CAP_WAIT_RECV_CONNECT_RSP:
-		case L2CAP_WAIT_CONFIG:
-		case L2CAP_OPEN: /* already established */
-			(*chan->lc_proto->linkmode)(chan->lc_upper, mode);
-			break;
-
-		default:
-			break;
-		}
-	}
-
-	link->hl_state = HCI_LINK_OPEN;
-	hci_acl_start(link);
-}
-
-/*
- * Receive ACL Data
- *
- * we accumulate packet fragments on the hci_link structure
- * until a full L2CAP frame is ready, then send it on.
- */
-void
-hci_acl_recv(struct mbuf *m, struct hci_unit *unit)
-{
-	struct hci_link *link;
-	hci_acldata_hdr_t hdr;
-	uint16_t handle, want;
-	int pb, got;
-
-	KKASSERT(m != NULL);
-	KKASSERT(unit != NULL);
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(hdr));
-	m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
-	m_adj(m, sizeof(hdr));
-
-#ifdef DIAGNOSTIC
-	if (hdr.type != HCI_ACL_DATA_PKT) {
-		kprintf("%s: bad ACL packet type\n",
-		    device_get_nameunit(unit->hci_dev));
-		goto bad;
-	}
-
-	if (m->m_pkthdr.len != letoh16(hdr.length)) {
-		kprintf("%s: bad ACL packet length (%d != %d)\n",
-		    device_get_nameunit(unit->hci_dev), m->m_pkthdr.len,
-		    letoh16(hdr.length));
-		goto bad;
-	}
-#endif
-
-	hdr.length = letoh16(hdr.length);
-	hdr.con_handle = letoh16(hdr.con_handle);
-	handle = HCI_CON_HANDLE(hdr.con_handle);
-	pb = HCI_PB_FLAG(hdr.con_handle);
-
-	link = hci_link_lookup_handle(unit, handle);
-	if (link == NULL) {
-		hci_discon_cp cp;
-
-		DPRINTF("%s: dumping packet for unknown handle #%d\n",
-		    device_get_nameunit(unit->hci_dev), handle);
-
-		/*
-		 * There is no way to find out what this connection handle is
-		 * for, just get rid of it. This may happen, if a USB dongle
-		 * is plugged into a self powered hub and does not reset when
-		 * the system is shut down.
-		 */
-		cp.con_handle = htole16(handle);
-		cp.reason = 0x13; /* "Remote User Terminated Connection" */
-		hci_send_cmd(unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp));
-		goto bad;
-	}
-
-	switch (pb) {
-	case HCI_PACKET_START:
-		if (link->hl_rxp != NULL)
-			kprintf("%s: dropped incomplete ACL packet\n",
-			    device_get_nameunit(unit->hci_dev));
-
-		if (m->m_pkthdr.len < sizeof(l2cap_hdr_t)) {
-			kprintf("%s: short ACL packet\n",
-			    device_get_nameunit(unit->hci_dev));
-
-			goto bad;
-		}
-
-		link->hl_rxp = m;
-		got = m->m_pkthdr.len;
-		break;
-
-	case HCI_PACKET_FRAGMENT:
-		if (link->hl_rxp == NULL) {
-			kprintf("%s: unexpected packet fragment\n",
-			    device_get_nameunit(unit->hci_dev));
-
-			goto bad;
-		}
-
-		got = m->m_pkthdr.len + link->hl_rxp->m_pkthdr.len;
-		m_cat(link->hl_rxp, m);
-		m = link->hl_rxp;
-		m->m_pkthdr.len = got;
-		break;
-
-	default:
-		kprintf("%s: unknown packet type\n",
-		    device_get_nameunit(unit->hci_dev));
-
-		goto bad;
-	}
-
-	m_copydata(m, 0, sizeof(want), (caddr_t)&want);
-	want = letoh16(want) + sizeof(l2cap_hdr_t) - got;
-
-	if (want > 0)
-		return;
-
-	link->hl_rxp = NULL;
-
-	if (want == 0) {
-		l2cap_recv_frame(m, link);
-		return;
-	}
-
-bad:
-	m_freem(m);
-}
-
-/*
- * Send ACL data on link
- *
- * We must fragment packets into chunks of less than unit->hci_max_acl_size and
- * prepend a relevant ACL header to each fragment. We keep a PDU structure
- * attached to the link, so that completed fragments can be marked off and
- * more data requested from above once the PDU is sent.
- */
-int
-hci_acl_send(struct mbuf *m, struct hci_link *link,
-		struct l2cap_channel *chan)
-{
-	struct l2cap_pdu *pdu;
-	struct mbuf *n = NULL;
-	int plen, mlen, num = 0;
-
-	KKASSERT(link != NULL);
-	KKASSERT(m != NULL);
-	KKASSERT(m->m_flags & M_PKTHDR);
-	KKASSERT(m->m_pkthdr.len > 0);
-
-	if (link->hl_state == HCI_LINK_CLOSED) {
-		m_freem(m);
-		return ENETDOWN;
-	}
-
-	pdu = zalloc(l2cap_pdu_pool);
-	if (pdu == NULL)
-		goto nomem;
-
-	bzero(pdu, sizeof *pdu);
-	pdu->lp_chan = chan;
-	pdu->lp_pending = 0;
-
-	plen = m->m_pkthdr.len;
-	mlen = link->hl_unit->hci_max_acl_size;
-
-	DPRINTFN(5, "%s: handle #%d, plen = %d, max = %d\n",
-	    device_get_nameunit(link->hl_unit->hci_dev),
-	    link->hl_handle, plen, mlen);
-
-	while (plen > 0) {
-		if (plen > mlen) {
-			n = m_split(m, mlen, M_NOWAIT);
-			if (n == NULL)
-				goto nomem;
-		} else {
-			mlen = plen;
-		}
-
-		if (num++ == 0)
-			m->m_flags |= M_PROTO1;	/* tag first fragment */
-
-		DPRINTFN(10, "(%s) chunk of %d (plen = %d) bytes\n",
-		    device_get_nameunit(link->hl_unit->hci_dev), mlen, plen);
-		IF_ENQUEUE(&pdu->lp_data, m);
-		m = n;
-		plen -= mlen;
-	}
-
-	TAILQ_INSERT_TAIL(&link->hl_txq, pdu, lp_next);
-	link->hl_txqlen += num;
-
-	hci_acl_start(link);
-
-	return 0;
-
-nomem:
-	if (m) m_freem(m);
-	if (pdu) {
-		IF_DRAIN(&pdu->lp_data);
-		zfree(l2cap_pdu_pool, pdu);
-	}
-
-	return ENOMEM;
-}
-
-/*
- * Start sending ACL data on link.
- *
- *	This is called when the queue may need restarting: as new data
- * is queued, after link mode changes have completed, or when device
- * buffers have cleared.
- *
- *	We may use all the available packet slots. The reason that we add
- * the ACL encapsulation here rather than in hci_acl_send() is that L2CAP
- * signal packets may be queued before the handle is given to us..
- */
-void
-hci_acl_start(struct hci_link *link)
-{
-	struct hci_unit *unit;
-	hci_acldata_hdr_t *hdr;
-	struct l2cap_pdu *pdu;
-	struct mbuf *m;
-	uint16_t handle;
-
-	KKASSERT(link != NULL);
-
-	unit = link->hl_unit;
-	KKASSERT(unit != NULL);
-
-	/* this is mainly to block ourselves (below) */
-	if (link->hl_state != HCI_LINK_OPEN)
-		return;
-
-	if (link->hl_txqlen == 0 || unit->hci_num_acl_pkts == 0)
-		return;
-
-	/* find first PDU with data to send */
-	pdu = TAILQ_FIRST(&link->hl_txq);
-	for (;;) {
-		if (pdu == NULL)
-			return;
-
-		if (!IF_QEMPTY(&pdu->lp_data))
-			break;
-
-		pdu = TAILQ_NEXT(pdu, lp_next);
-	}
-
-	while (unit->hci_num_acl_pkts > 0) {
-		IF_DEQUEUE(&pdu->lp_data, m);
-		KKASSERT(m != NULL);
-
-		if (m->m_flags & M_PROTO1)
-			handle = HCI_MK_CON_HANDLE(link->hl_handle,
-						HCI_PACKET_START, 0);
-		else
-			handle = HCI_MK_CON_HANDLE(link->hl_handle,
-						HCI_PACKET_FRAGMENT, 0);
-
-		M_PREPEND(m, sizeof(*hdr), M_NOWAIT);
-		if (m == NULL)
-			break;
-
-		hdr = mtod(m, hci_acldata_hdr_t *);
-		hdr->type = HCI_ACL_DATA_PKT;
-		hdr->con_handle = htole16(handle);
-		hdr->length = htole16(m->m_pkthdr.len - sizeof(*hdr));
-
-		link->hl_txqlen--;
-		pdu->lp_pending++;
-
-		hci_output_acl(unit, m);
-
-		if (IF_QEMPTY(&pdu->lp_data)) {
-			if (pdu->lp_chan) {
-				/*
-				 * This should enable streaming of PDUs - when
-				 * we have placed all the fragments on the acl
-				 * output queue, we trigger the L2CAP layer to
-				 * send us down one more. Use a false state so
-				 * we dont run into ourselves coming back from
-				 * the future..
-				 */
-				link->hl_state = HCI_LINK_BLOCK;
-				l2cap_start(pdu->lp_chan);
-				link->hl_state = HCI_LINK_OPEN;
-			}
-
-			pdu = TAILQ_NEXT(pdu, lp_next);
-			if (pdu == NULL)
-				break;
-		}
-	}
-
-	/*
-	 * We had our turn now, move to the back of the queue to let
-	 * other links have a go at the output buffers..
-	 */
-	if (TAILQ_NEXT(link, hl_next)) {
-		TAILQ_REMOVE(&unit->hci_links, link, hl_next);
-		TAILQ_INSERT_TAIL(&unit->hci_links, link, hl_next);
-	}
-}
-
-/*
- * Confirm ACL packets cleared from Controller buffers. We scan our PDU
- * list to clear pending fragments and signal upstream for more data
- * when a PDU is complete.
- */
-void
-hci_acl_complete(struct hci_link *link, int num)
-{
-	struct l2cap_pdu *pdu;
-	struct l2cap_channel *chan;
-
-	DPRINTFN(5, "(%s) handle #%d (%d)\n",
-	    device_get_nameunit(link->hl_unit->hci_dev), link->hl_handle, num);
-
-	while (num > 0) {
-		pdu = TAILQ_FIRST(&link->hl_txq);
-		if (pdu == NULL) {
-			kprintf("%s: %d packets completed on handle #%x "
-				"but none pending!\n",
-				device_get_nameunit(link->hl_unit->hci_dev),
-				num, link->hl_handle);
-			return;
-		}
-
-		if (num >= pdu->lp_pending) {
-			num -= pdu->lp_pending;
-			pdu->lp_pending = 0;
-
-			if (IF_QEMPTY(&pdu->lp_data)) {
-				TAILQ_REMOVE(&link->hl_txq, pdu, lp_next);
-				chan = pdu->lp_chan;
-				if (chan != NULL) {
-					chan->lc_pending--;
-					(*chan->lc_proto->complete)
-							(chan->lc_upper, 1);
-
-					if (chan->lc_pending == 0)
-						l2cap_start(chan);
-				}
-
-				zfree(l2cap_pdu_pool, pdu);
-			}
-		} else {
-			pdu->lp_pending -= num;
-			num = 0;
-		}
-	}
-}
-
-/*******************************************************************************
- *
- *	HCI SCO Connections
- */
-
-/*
- * Incoming SCO Connection. We check the list for anybody willing
- * to take it.
- */
-struct hci_link *
-hci_sco_newconn(struct hci_unit *unit, bdaddr_t *bdaddr)
-{
-	struct sockaddr_bt laddr, raddr;
-	struct sco_pcb *pcb, *new;
-	struct hci_link *sco, *acl;
-
-	memset(&laddr, 0, sizeof(laddr));
-	laddr.bt_len = sizeof(laddr);
-	laddr.bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&laddr.bt_bdaddr, &unit->hci_bdaddr);
-
-	memset(&raddr, 0, sizeof(raddr));
-	raddr.bt_len = sizeof(raddr);
-	raddr.bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&raddr.bt_bdaddr, bdaddr);
-
-	/*
-	 * There should already be an ACL link up and running before
-	 * the controller sends us SCO connection requests, but you
-	 * never know..
-	 */
-	acl = hci_link_lookup_bdaddr(unit, bdaddr, HCI_LINK_ACL);
-	if (acl == NULL || acl->hl_state != HCI_LINK_OPEN)
-		return NULL;
-
-	LIST_FOREACH(pcb, &sco_pcb, sp_next) {
-		if ((pcb->sp_flags & SP_LISTENING) == 0)
-			continue;
-
-		new = (*pcb->sp_proto->newconn)(pcb->sp_upper, &laddr, &raddr);
-		if (new == NULL)
-			continue;
-
-		/*
-		 * Ok, got new pcb so we can start a new link and fill
-		 * in all the details.
-		 */
-		bdaddr_copy(&new->sp_laddr, &unit->hci_bdaddr);
-		bdaddr_copy(&new->sp_raddr, bdaddr);
-
-		sco = hci_link_alloc(unit);
-		if (sco == NULL) {
-			sco_detach(&new);
-			return NULL;
-		}
-
-		sco->hl_type = HCI_LINK_SCO;
-		bdaddr_copy(&sco->hl_bdaddr, bdaddr);
-
-		sco->hl_link = hci_acl_open(unit, bdaddr);
-		KKASSERT(sco->hl_link == acl);
-
-		sco->hl_sco = new;
-		new->sp_link = sco;
-
-		new->sp_mtu = unit->hci_max_sco_size;
-		return sco;
-	}
-
-	return NULL;
-}
-
-/*
- * receive SCO packet, we only need to strip the header and send
- * it to the right handler
- */
-void
-hci_sco_recv(struct mbuf *m, struct hci_unit *unit)
-{
-	struct hci_link *link;
-	hci_scodata_hdr_t hdr;
-	uint16_t handle;
-
-	KKASSERT(m != NULL);
-	KKASSERT(unit != NULL);
-
-	KKASSERT(m->m_pkthdr.len >= sizeof(hdr));
-	m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
-	m_adj(m, sizeof(hdr));
-
-#ifdef DIAGNOSTIC
-	if (hdr.type != HCI_SCO_DATA_PKT) {
-		kprintf("%s: bad SCO packet type\n",
-		    device_get_nameunit(unit->hci_dev));
-		goto bad;
-	}
-
-	if (m->m_pkthdr.len != hdr.length) {
-		kprintf("%s: bad SCO packet length (%d != %d)\n",
-		    device_get_nameunit(unit->hci_dev), m->m_pkthdr.len,
-		    hdr.length);
-		goto bad;
-	}
-#endif
-
-	hdr.con_handle = letoh16(hdr.con_handle);
-	handle = HCI_CON_HANDLE(hdr.con_handle);
-
-	link = hci_link_lookup_handle(unit, handle);
-	if (link == NULL || link->hl_type == HCI_LINK_ACL) {
-		DPRINTF("%s: dumping packet for unknown handle #%d\n",
-		    device_get_nameunit(unit->hci_dev), handle);
-
-		goto bad;
-	}
-
-	(*link->hl_sco->sp_proto->input)(link->hl_sco->sp_upper, m);
-	return;
-
-bad:
-	m_freem(m);
-}
-
-void
-hci_sco_start(struct hci_link *link)
-{
-}
-
-/*
- * SCO packets have completed at the controller, so we can
- * signal up to free the buffer space.
- */
-void
-hci_sco_complete(struct hci_link *link, int num)
-{
-
-	DPRINTFN(5, "handle #%d (num=%d)\n", link->hl_handle, num);
-	link->hl_sco->sp_pending--;
-	(*link->hl_sco->sp_proto->complete)(link->hl_sco->sp_upper, num);
-}
-
-/*******************************************************************************
- *
- *	Generic HCI Connection alloc/free/lookup etc
- */
-
-struct hci_link *
-hci_link_alloc(struct hci_unit *unit)
-{
-	struct hci_link *link;
-
-	KKASSERT(unit != NULL);
-
-	link = kmalloc(sizeof *link, M_BLUETOOTH, M_NOWAIT | M_ZERO);
-	if (link == NULL)
-		return NULL;
-
-	link->hl_unit = unit;
-	link->hl_state = HCI_LINK_CLOSED;
-
-	/* init ACL portion */
-	callout_init(&link->hl_expire);
-
-	crit_enter();
-	TAILQ_INIT(&link->hl_txq);	/* outgoing packets */
-	TAILQ_INIT(&link->hl_reqs);	/* request queue */
-
-	link->hl_mtu = L2CAP_MTU_DEFAULT;		/* L2CAP signal mtu */
-	link->hl_flush = L2CAP_FLUSH_TIMO_DEFAULT;	/* flush timeout */
-
-	/* init SCO portion */
-	/* &link->hl_data is already zero-initialized. */
-
-	/* attach to unit */
-	TAILQ_INSERT_HEAD(&unit->hci_links, link, hl_next);
-	crit_exit();	
-	return link;
-}
-
-void
-hci_link_free(struct hci_link *link, int err)
-{
-	struct l2cap_req *req;
-	struct l2cap_pdu *pdu;
-	struct l2cap_channel *chan, *next;
-
-	KKASSERT(link != NULL);
-
-	DPRINTF("(%s) #%d, type = %d, state = %d, refcnt = %d\n",
-	    device_get_nameunit(link->hl_unit->hci_dev), link->hl_handle,
-	    link->hl_type, link->hl_state, link->hl_refcnt);
-
-	/* ACL reference count */
-	if (link->hl_refcnt > 0) {
-		next = LIST_FIRST(&l2cap_active_list);
-		while ((chan = next) != NULL) {
-			next = LIST_NEXT(chan, lc_ncid);
-			if (chan->lc_link == link)
-				l2cap_close(chan, err);
-		}
-	}
-	KKASSERT(link->hl_refcnt == 0);
-
-	/* ACL L2CAP requests.. */
-	while ((req = TAILQ_FIRST(&link->hl_reqs)) != NULL)
-		l2cap_request_free(req);
-
-	KKASSERT(TAILQ_EMPTY(&link->hl_reqs));
-
-	/* ACL outgoing data queue */
-	while ((pdu = TAILQ_FIRST(&link->hl_txq)) != NULL) {
-		TAILQ_REMOVE(&link->hl_txq, pdu, lp_next);
-		IF_DRAIN(&pdu->lp_data);
-		if (pdu->lp_pending)
-			link->hl_unit->hci_num_acl_pkts += pdu->lp_pending;
-
-		zfree(l2cap_pdu_pool, pdu);
-	}
-
-	KKASSERT(TAILQ_EMPTY(&link->hl_txq));
-
-	/* ACL incoming data packet */
-	if (link->hl_rxp != NULL) {
-		m_freem(link->hl_rxp);
-		link->hl_rxp = NULL;
-	}
-
-	/* SCO master ACL link */
-	if (link->hl_link != NULL) {
-		hci_acl_close(link->hl_link, err);
-		link->hl_link = NULL;
-	}
-
-	/* SCO pcb */
-	if (link->hl_sco != NULL) {
-		struct sco_pcb *pcb;
-
-		pcb = link->hl_sco;
-		pcb->sp_link = NULL;
-		link->hl_sco = NULL;
-		(*pcb->sp_proto->disconnected)(pcb->sp_upper, err);
-	}
-
-	/* flush any SCO data */
-	crit_enter();	
-	IF_DRAIN(&link->hl_data);
-	crit_exit();
-
-	/*
-	 * Halt the timeout - if its already running we cannot free the
-	 * link structure but the timeout function will call us back in
-	 * any case.
-	 */
-	link->hl_state = HCI_LINK_CLOSED;
-	callout_stop(&link->hl_expire);
-	if (callout_active(&link->hl_expire))
-		return;
-
-	/*
-	 * If we made a note of clock offset, keep it in a memo
-	 * to facilitate reconnections to this device
-	 */
-	if (link->hl_clock != 0) {
-		struct hci_memo *memo;
-
-		memo = hci_memo_new(link->hl_unit, &link->hl_bdaddr);
-		if (memo != NULL)
-			memo->clock_offset = link->hl_clock;
-	}
-
-	crit_enter();
-	TAILQ_REMOVE(&link->hl_unit->hci_links, link, hl_next);
-	crit_exit();	
-	kfree(link, M_BLUETOOTH);
-}
-
-/*
- * Lookup HCI link by type and state.
- */
-struct hci_link *
-hci_link_lookup_state(struct hci_unit *unit, uint16_t type, uint16_t state)
-{
-	struct hci_link *link;
-
-	TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
-		if (link->hl_type == type && link->hl_state == state)
-			break;
-	}
-
-	return link;
-}
-
-/*
- * Lookup HCI link by address and type. Note that for SCO links there may
- * be more than one link per address, so we only return links with no
- * handle (ie new links)
- */
-struct hci_link *
-hci_link_lookup_bdaddr(struct hci_unit *unit, bdaddr_t *bdaddr, uint16_t type)
-{
-	struct hci_link *link;
-
-	KKASSERT(unit != NULL);
-	KKASSERT(bdaddr != NULL);
-
-	TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
-		if (link->hl_type != type)
-			continue;
-
-		if (type == HCI_LINK_SCO && link->hl_handle != 0)
-			continue;
-
-		if (bdaddr_same(&link->hl_bdaddr, bdaddr))
-			break;
-	}
-
-	return link;
-}
-
-struct hci_link *
-hci_link_lookup_handle(struct hci_unit *unit, uint16_t handle)
-{
-	struct hci_link *link;
-
-	KKASSERT(unit != NULL);
-
-	TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
-		if (handle == link->hl_handle)
-			break;
-	}
-
-	return link;
-}
diff --git a/sys/netbt/hci_misc.c b/sys/netbt/hci_misc.c
deleted file mode 100644
index 7e92564533..0000000000
--- a/sys/netbt/hci_misc.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/* $OpenBSD: src/sys/netbt/hci_misc.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: hci_misc.c,v 1.3 2007/09/16 19:59:30 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/queue.h>
-#include <sys/systm.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-
-/*
- * cache Inquiry Responses for this number of seconds for routing
- * purposes [sysctl]
- */
-int hci_memo_expiry = 600;
-
-/*
- * set 'src' address for routing to 'dest'
- */
-int
-hci_route_lookup(bdaddr_t *src, bdaddr_t *dest)
-{
-	struct hci_unit *unit;
-	struct hci_link *link;
-	struct hci_memo *memo;
-
-	/*
-	 * Walk the ACL connections, if we have a connection
-	 * to 'dest' already then thats best..
-	 */
-	TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
-		if ((unit->hci_flags & BTF_UP) == 0)
-			continue;
-
-		TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
-			if (link->hl_type != HCI_LINK_ACL)
-				continue;
-
-			if (bdaddr_same(&link->hl_bdaddr, dest))
-				goto found;
-		}
-	}
-
-	/*
-	 * Now check all the memos to see if there has been an
-	 * inquiry repsonse..
-	 */
-	TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
-		if ((unit->hci_flags & BTF_UP) == 0)
-			continue;
-
-		memo = hci_memo_find(unit, dest);
-		if (memo)
-			goto found;
-	}
-
-	/*
-	 * Last ditch effort, lets use the first unit we find
-	 * thats up and running. (XXX settable default route?)
-	 */
-	TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
-		if ((unit->hci_flags & BTF_UP) == 0)
-			continue;
-
-		goto found;
-	}
-
-	return EHOSTUNREACH;
-
-found:
-	bdaddr_copy(src, &unit->hci_bdaddr);
-	return 0;
-}
-
-/*
- * find unit memo from bdaddr
- */
-struct hci_memo *
-hci_memo_find(struct hci_unit *unit, bdaddr_t *bdaddr)
-{
-	struct hci_memo *memo, *m0;
-	struct timeval now;
-
-	microtime(&now);
-
-	m0 = LIST_FIRST(&unit->hci_memos);
-	while ((memo = m0) != NULL) {
-		m0 = LIST_NEXT(memo, next);
-
-		if (now.tv_sec > memo->time.tv_sec + hci_memo_expiry) {
-			DPRINTF("memo %p too old (expiring)\n", memo);
-			hci_memo_free(memo);
-			continue;
-		}
-
-		if (bdaddr_same(bdaddr, &memo->bdaddr)) {
-			DPRINTF("memo %p found\n", memo);
-			return memo;
-		}
-	}
-
-	DPRINTF("no memo found\n");
-	return NULL;
-}
-
-/*
- * Make a new memo on unit for bdaddr. If a memo exists, just
- * update the timestamp.
- */
-struct hci_memo *
-hci_memo_new(struct hci_unit *unit, bdaddr_t *bdaddr)
-{
-	struct hci_memo *memo;
-
-	memo = hci_memo_find(unit, bdaddr);
-	if (memo == NULL) {
-		memo = kmalloc(sizeof(struct hci_memo),
-			M_BLUETOOTH, M_NOWAIT | M_ZERO);
-
-		if (memo == NULL) {
-			DPRINTFN(0, "no memory for memo!\n");
-			return NULL;
-		}
-
-		DPRINTF("memo created for %02x:%02x:%02x:%02x:%02x:%02x\n",
-			bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
-			bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
-
-		bdaddr_copy(&memo->bdaddr, bdaddr);
-		LIST_INSERT_HEAD(&unit->hci_memos, memo, next);
-	}
-	else
-		DPRINTF("memo updated for %02x:%02x:%02x:%02x:%02x:%02x\n",
-			bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
-			bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
-
-	microtime(&memo->time);
-	return memo;
-}
-
-void
-hci_memo_free(struct hci_memo *memo)
-{
-
-	LIST_REMOVE(memo, next);
-	kfree(memo, M_BLUETOOTH);
-}
diff --git a/sys/netbt/hci_socket.c b/sys/netbt/hci_socket.c
deleted file mode 100644
index a725ea5306..0000000000
--- a/sys/netbt/hci_socket.c
+++ /dev/null
@@ -1,1034 +0,0 @@
-/* $OpenBSD: src/sys/netbt/hci_socket.c,v 1.5 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: hci_socket.c,v 1.14 2008/02/10 17:40:54 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
-
-/* load symbolic names */
-#ifdef BLUETOOTH_DEBUG
-#define PRUREQUESTS
-#define PRCOREQUESTS
-#endif
-
-#include <sys/param.h>
-#include <sys/domain.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/priv.h>
-#include <sys/protosw.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/systm.h>
-#include <sys/endian.h>
-#include <net/if.h>
-#include <net/if_var.h>
-#include <sys/sysctl.h>
-
-#include <sys/thread2.h>
-#include <sys/socketvar2.h>
-#include <sys/msgport2.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-
-/*******************************************************************************
- *
- * HCI SOCK_RAW Sockets - for control of Bluetooth Devices
- *
- */
-
-/*
- * the raw HCI protocol control block
- */
-struct hci_pcb {
-	struct socket		*hp_socket;	/* socket */
-	unsigned int		hp_flags;	/* flags */
-	bdaddr_t		hp_laddr;	/* local address */
-	bdaddr_t		hp_raddr;	/* remote address */
-	struct hci_filter	hp_efilter;	/* user event filter */
-	struct hci_filter	hp_pfilter;	/* user packet filter */
-	LIST_ENTRY(hci_pcb)	hp_next;	/* next HCI pcb */
-};
-
-/* hp_flags */
-#define HCI_PRIVILEGED		(1<<0)	/* no security filter for root */
-#define HCI_DIRECTION		(1<<1)	/* direction control messages */
-#define HCI_PROMISCUOUS		(1<<2)	/* listen to all units */
-
-LIST_HEAD(hci_pcb_list, hci_pcb) hci_pcb = LIST_HEAD_INITIALIZER(hci_pcb);
-
-/* sysctl defaults */
-int hci_sendspace = HCI_CMD_PKT_SIZE;
-int hci_recvspace = 4096;
-
-extern struct pr_usrreqs hci_usrreqs;
-
-/* Prototypes for usrreqs methods. */
-static void hci_sdetach(netmsg_t msg);
-
-/* supported commands opcode table */
-static const struct {
-	uint16_t	opcode;
-	uint8_t		offs;	/* 0 - 63 */
-	uint8_t		mask;	/* bit 0 - 7 */
-	int16_t		length;	/* -1 if privileged */
-} hci_cmds[] = {
-	{ HCI_CMD_INQUIRY,
-	  0,  0x01, sizeof(hci_inquiry_cp) },
-	{ HCI_CMD_INQUIRY_CANCEL,
-	  0,  0x02, -1 },
-	{ HCI_CMD_PERIODIC_INQUIRY,
-	  0,  0x04, -1 },
-	{ HCI_CMD_EXIT_PERIODIC_INQUIRY,
-	  0,  0x08, -1 },
-	{ HCI_CMD_CREATE_CON,
-	  0,  0x10, -1 },
-	{ HCI_CMD_DISCONNECT,
-	  0,  0x20, -1 },
-	{ HCI_CMD_ADD_SCO_CON,
-	  0,  0x40, -1 },
-	{ HCI_CMD_CREATE_CON_CANCEL,
-	  0,  0x80, -1 },
-	{ HCI_CMD_ACCEPT_CON,
-	  1,  0x01, -1 },
-	{ HCI_CMD_REJECT_CON,
-	  1,  0x02, -1 },
-	{ HCI_CMD_LINK_KEY_REP,
-	  1,  0x04, -1 },
-	{ HCI_CMD_LINK_KEY_NEG_REP,
-	  1,  0x08, -1 },
-	{ HCI_CMD_PIN_CODE_REP,
-	  1,  0x10, -1 },
-	{ HCI_CMD_PIN_CODE_NEG_REP,
-	  1,  0x20, -1 },
-	{ HCI_CMD_CHANGE_CON_PACKET_TYPE,
-	  1,  0x40, -1 },
-	{ HCI_CMD_AUTH_REQ,
-	  1,  0x80, -1 },
-	{ HCI_CMD_SET_CON_ENCRYPTION,
-	  2,  0x01, -1 },
-	{ HCI_CMD_CHANGE_CON_LINK_KEY,
-	  2,  0x02, -1 },
-	{ HCI_CMD_MASTER_LINK_KEY,
-	  2,  0x04, -1 },
-	{ HCI_CMD_REMOTE_NAME_REQ,
-	  2,  0x08, sizeof(hci_remote_name_req_cp) },
-	{ HCI_CMD_REMOTE_NAME_REQ_CANCEL,
-	  2,  0x10, -1 },
-	{ HCI_CMD_READ_REMOTE_FEATURES,
-	  2,  0x20, sizeof(hci_read_remote_features_cp) },
-	{ HCI_CMD_READ_REMOTE_EXTENDED_FEATURES,
-	  2,  0x40, sizeof(hci_read_remote_extended_features_cp) },
-	{ HCI_CMD_READ_REMOTE_VER_INFO,
-	  2,  0x80, sizeof(hci_read_remote_ver_info_cp) },
-	{ HCI_CMD_READ_CLOCK_OFFSET,
-	  3,  0x01, sizeof(hci_read_clock_offset_cp) },
-	{ HCI_CMD_READ_LMP_HANDLE,
-	  3,  0x02, sizeof(hci_read_lmp_handle_cp) },
-	{ HCI_CMD_HOLD_MODE,
-	  4,  0x02, -1 },
-	{ HCI_CMD_SNIFF_MODE,
-	  4,  0x04, -1 },
-	{ HCI_CMD_EXIT_SNIFF_MODE,
-	  4,  0x08, -1 },
-	{ HCI_CMD_PARK_MODE,
-	  4,  0x10, -1 },
-	{ HCI_CMD_EXIT_PARK_MODE,
-	  4,  0x20, -1 },
-	{ HCI_CMD_QOS_SETUP,
-	  4,  0x40, -1 },
-	{ HCI_CMD_ROLE_DISCOVERY,
-	  4,  0x80, sizeof(hci_role_discovery_cp) },
-	{ HCI_CMD_SWITCH_ROLE,
-	  5,  0x01, -1 },
-	{ HCI_CMD_READ_LINK_POLICY_SETTINGS,
-	  5,  0x02, sizeof(hci_read_link_policy_settings_cp) },
-	{ HCI_CMD_WRITE_LINK_POLICY_SETTINGS,
-	  5,  0x04, -1 },
-	{ HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS,
-	  5,  0x08, 0 },
-	{ HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS,
-	  5,  0x10, -1 },
-	{ HCI_CMD_FLOW_SPECIFICATION,
-	  5,  0x20, -1 },
-	{ HCI_CMD_SET_EVENT_MASK,
-	  5,  0x40, -1 },
-	{ HCI_CMD_RESET,
-	  5,  0x80, -1 },
-	{ HCI_CMD_SET_EVENT_FILTER,
-	  6,  0x01, -1 },
-	{ HCI_CMD_FLUSH,
-	  6,  0x02, -1 },
-	{ HCI_CMD_READ_PIN_TYPE,
-	  6,  0x04, 0 },
-	{ HCI_CMD_WRITE_PIN_TYPE,
-	  6,  0x08, -1 },
-	{ HCI_CMD_CREATE_NEW_UNIT_KEY,
-	  6,  0x10, -1 },
-	{ HCI_CMD_READ_STORED_LINK_KEY,
-	  6,  0x20, -1 },
-	{ HCI_CMD_WRITE_STORED_LINK_KEY,
-	  6,  0x40, -1 },
-	{ HCI_CMD_DELETE_STORED_LINK_KEY,
-	  6,  0x80, -1 },
-	{ HCI_CMD_WRITE_LOCAL_NAME,
-	  7,  0x01, -1 },
-	{ HCI_CMD_READ_LOCAL_NAME,
-	  7,  0x02, 0 },
-	{ HCI_CMD_READ_CON_ACCEPT_TIMEOUT,
-	  7,  0x04, 0 },
-	{ HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT,
-	  7,  0x08, -1 },
-	{ HCI_CMD_READ_PAGE_TIMEOUT,
-	  7,  0x10, 0 },
-	{ HCI_CMD_WRITE_PAGE_TIMEOUT,
-	  7,  0x20, -1 },
-	{ HCI_CMD_READ_SCAN_ENABLE,
-	  7,  0x40, 0 },
-	{ HCI_CMD_WRITE_SCAN_ENABLE,
-	  7,  0x80, -1 },
-	{ HCI_CMD_READ_PAGE_SCAN_ACTIVITY,
-	  8,  0x01, 0 },
-	{ HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY,
-	  8,  0x02, -1 },
-	{ HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY,
-	  8,  0x04, 0 },
-	{ HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY,
-	  8,  0x08, -1 },
-	{ HCI_CMD_READ_AUTH_ENABLE,
-	  8,  0x10, 0 },
-	{ HCI_CMD_WRITE_AUTH_ENABLE,
-	  8,  0x20, -1 },
-	{ HCI_CMD_READ_ENCRYPTION_MODE,
-	  8,  0x40, 0 },
-	{ HCI_CMD_WRITE_ENCRYPTION_MODE,
-	  8,  0x80, -1 },
-	{ HCI_CMD_READ_UNIT_CLASS,
-	  9,  0x01, 0 },
-	{ HCI_CMD_WRITE_UNIT_CLASS,
-	  9,  0x02, -1 },
-	{ HCI_CMD_READ_VOICE_SETTING,
-	  9,  0x04, 0 },
-	{ HCI_CMD_WRITE_VOICE_SETTING,
-	  9,  0x08, -1 },
-	{ HCI_CMD_READ_AUTO_FLUSH_TIMEOUT,
-	  9,  0x10, sizeof(hci_read_auto_flush_timeout_cp) },
-	{ HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT,
-	  9,  0x20, -1 },
-	{ HCI_CMD_READ_NUM_BROADCAST_RETRANS,
-	  9,  0x40, 0 },
-	{ HCI_CMD_WRITE_NUM_BROADCAST_RETRANS,
-	  9,  0x80, -1 },
-	{ HCI_CMD_READ_HOLD_MODE_ACTIVITY,
-	  10, 0x01, 0 },
-	{ HCI_CMD_WRITE_HOLD_MODE_ACTIVITY,
-	  10, 0x02, -1 },
-	{ HCI_CMD_READ_XMIT_LEVEL,
-	  10, 0x04, sizeof(hci_read_xmit_level_cp) },
-	{ HCI_CMD_READ_SCO_FLOW_CONTROL,
-	  10, 0x08, 0 },
-	{ HCI_CMD_WRITE_SCO_FLOW_CONTROL,
-	  10, 0x10, -1 },
-	{ HCI_CMD_HC2H_FLOW_CONTROL,
-	  10, 0x20, -1 },
-	{ HCI_CMD_HOST_BUFFER_SIZE,
-	  10, 0x40, -1 },
-	{ HCI_CMD_HOST_NUM_COMPL_PKTS,
-	  10, 0x80, -1 },
-	{ HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT,
-	  11, 0x01, sizeof(hci_read_link_supervision_timeout_cp) },
-	{ HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT,
-	  11, 0x02, -1 },
-	{ HCI_CMD_READ_NUM_SUPPORTED_IAC,
-	  11, 0x04, 0 },
-	{ HCI_CMD_READ_IAC_LAP,
-	  11, 0x08, 0 },
-	{ HCI_CMD_WRITE_IAC_LAP,
-	  11, 0x10, -1 },
-	{ HCI_CMD_READ_PAGE_SCAN_PERIOD,
-	  11, 0x20, 0 },
-	{ HCI_CMD_WRITE_PAGE_SCAN_PERIOD,
-	  11, 0x40, -1 },
-	{ HCI_CMD_READ_PAGE_SCAN,
-	  11, 0x80, 0 },
-	{ HCI_CMD_WRITE_PAGE_SCAN,
-	  12, 0x01, -1 },
-	{ HCI_CMD_SET_AFH_CLASSIFICATION,
-	  12, 0x02, -1 },
-	{ HCI_CMD_READ_INQUIRY_SCAN_TYPE,
-	  12, 0x10, 0 },
-	{ HCI_CMD_WRITE_INQUIRY_SCAN_TYPE,
-	  12, 0x20, -1 },
-	{ HCI_CMD_READ_INQUIRY_MODE,
-	  12, 0x40, 0 },
-	{ HCI_CMD_WRITE_INQUIRY_MODE,
-	  12, 0x80, -1 },
-	{ HCI_CMD_READ_PAGE_SCAN_TYPE,
-	  13, 0x01, 0 },
-	{ HCI_CMD_WRITE_PAGE_SCAN_TYPE,
-	  13, 0x02, -1 },
-	{ HCI_CMD_READ_AFH_ASSESSMENT,
-	  13, 0x04, 0 },
-	{ HCI_CMD_WRITE_AFH_ASSESSMENT,
-	  13, 0x08, -1 },
-	{ HCI_CMD_READ_LOCAL_VER,
-	  14, 0x08, 0 },
-	{ HCI_CMD_READ_LOCAL_COMMANDS,
-	  14, 0x10, 0 },
-	{ HCI_CMD_READ_LOCAL_FEATURES,
-	  14, 0x20, 0 },
-	{ HCI_CMD_READ_LOCAL_EXTENDED_FEATURES,
-	  14, 0x40, sizeof(hci_read_local_extended_features_cp) },
-	{ HCI_CMD_READ_BUFFER_SIZE,
-	  14, 0x80, 0 },
-	{ HCI_CMD_READ_COUNTRY_CODE,
-	  15, 0x01, 0 },
-	{ HCI_CMD_READ_BDADDR,
-	  15, 0x02, 0 },
-	{ HCI_CMD_READ_FAILED_CONTACT_CNTR,
-	  15, 0x04, sizeof(hci_read_failed_contact_cntr_cp) },
-	{ HCI_CMD_RESET_FAILED_CONTACT_CNTR,
-	  15, 0x08, -1 },
-	{ HCI_CMD_READ_LINK_QUALITY,
-	  15, 0x10, sizeof(hci_read_link_quality_cp) },
-	{ HCI_CMD_READ_RSSI,
-	  15, 0x20, sizeof(hci_read_rssi_cp) },
-	{ HCI_CMD_READ_AFH_CHANNEL_MAP,
-	  15, 0x40, sizeof(hci_read_afh_channel_map_cp) },
-	{ HCI_CMD_READ_CLOCK,
-	  15, 0x80, sizeof(hci_read_clock_cp) },
-	{ HCI_CMD_READ_LOOPBACK_MODE,
-	  16, 0x01, 0 },
-	{ HCI_CMD_WRITE_LOOPBACK_MODE,
-	  16, 0x02, -1 },
-	{ HCI_CMD_ENABLE_UNIT_UNDER_TEST,
-	  16, 0x04, -1 },
-	{ HCI_CMD_SETUP_SCO_CON,
-	  16, 0x08, -1 },
-	{ HCI_CMD_ACCEPT_SCO_CON_REQ,
-	  16, 0x10, -1 },
-	{ HCI_CMD_REJECT_SCO_CON_REQ,
-	  16, 0x20, -1 },
-	{ HCI_CMD_READ_EXTENDED_INQUIRY_RSP,
-	  17, 0x01, 0 },
-	{ HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP,
-	  17, 0x02, -1 },
-	{ HCI_CMD_REFRESH_ENCRYPTION_KEY,
-	  17, 0x04, -1 },
-	{ HCI_CMD_SNIFF_SUBRATING,
-	  17, 0x10, -1 },
-	{ HCI_CMD_READ_SIMPLE_PAIRING_MODE,
-	  17, 0x20, 0 },
-	{ HCI_CMD_WRITE_SIMPLE_PAIRING_MODE,
-	  17, 0x40, -1 },
-	{ HCI_CMD_READ_LOCAL_OOB_DATA,
-	  17, 0x80, -1 },
-	{ HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER,
-	  18, 0x01, 0 },
-	{ HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER,
-	  18, 0x02, -1 },
-	{ HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING,
-	  18, 0x04, 0 },
-	{ HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING,
-	  18, 0x08, -1 },
-	{ HCI_CMD_IO_CAPABILITY_REP,
-	  18, 0x80, -1 },
-	{ HCI_CMD_USER_CONFIRM_REP,
-	  19, 0x01, -1 },
-	{ HCI_CMD_USER_CONFIRM_NEG_REP,
-	  19, 0x02, -1 },
-	{ HCI_CMD_USER_PASSKEY_REP,
-	  19, 0x04, -1 },
-	{ HCI_CMD_USER_PASSKEY_NEG_REP,
-	  19, 0x08, -1 },
-	{ HCI_CMD_OOB_DATA_REP,
-	  19, 0x10, -1 },
-	{ HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE,
-	  19, 0x20, -1 },
-	{ HCI_CMD_ENHANCED_FLUSH,
-	  19, 0x40, -1 },
-	{ HCI_CMD_OOB_DATA_NEG_REP,
-	  19, 0x80, -1 },
-	{ HCI_CMD_SEND_KEYPRESS_NOTIFICATION,
-	  20, 0x40, -1 },
-	{ HCI_CMD_IO_CAPABILITY_NEG_REP,
-	  20, 0x80, -1 },
-};
-
-/*
- * Security filter routines for unprivileged users.
- *	Allow all but a few critical events, and only permit read commands.
- *	If a unit is given, verify the command is supported.
- */
-
-static int
-hci_security_check_opcode(struct hci_unit *unit, uint16_t opcode)
-{
-	int i;
-
-	for (i = 0 ; i < NELEM(hci_cmds); i++) {
-		if (opcode != hci_cmds[i].opcode)
-			continue;
-
-		if (unit == NULL
-		    || (unit->hci_cmds[hci_cmds[i].offs] & hci_cmds[i].mask))
-			return hci_cmds[i].length;
-
-		break;
-	}
-
-	return -1;
-}
-
-static int
-hci_security_check_event(uint8_t event)
-{
-
-	switch (event) {
-	case HCI_EVENT_RETURN_LINK_KEYS:
-	case HCI_EVENT_LINK_KEY_NOTIFICATION:
-	case HCI_EVENT_USER_CONFIRM_REQ:
-	case HCI_EVENT_USER_PASSKEY_NOTIFICATION:
-	case HCI_EVENT_VENDOR:
-		return -1;	/* disallowed */
-	}
-
-	return 0;	/* ok */
-}
-
-/*
- * When command packet reaches the device, we can drop
- * it from the socket buffer (called from hci_output_acl)
- */
-void
-hci_drop(void *arg)
-{
-	struct socket *so = arg;
-
-	sbdroprecord(&so->so_snd.sb);
-	sowwakeup(so);
-}
-
-/*
- * HCI socket is going away and has some pending packets. We let them
- * go by design, but remove the context pointer as it will be invalid
- * and we no longer need to be notified.
- */
-static void
-hci_cmdwait_flush(struct socket *so)
-{
-	struct hci_unit *unit;
-	struct socket *ctx;
-	struct mbuf *m;
-
-	DPRINTF("flushing %p\n", so);
-
-	TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
-		IF_POLL(&unit->hci_cmdwait, m);
-		while (m != NULL) {
-			ctx = M_GETCTX(m, struct socket *);
-			if (ctx == so)
-				M_SETCTX(m, NULL);
-
-			m = m->m_nextpkt;
-		}
-	}
-}
-
-/*
- * HCI send packet
- *     This came from userland, so check it out.
- */
-static int
-hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr)
-{
-	struct hci_unit *unit;
-	struct mbuf *m0;
-	hci_cmd_hdr_t hdr;
-	int err;
-
-	KKASSERT(m != NULL);
-	KKASSERT(addr != NULL);
-
-	/* wants at least a header to start with */
-	if (m->m_pkthdr.len < sizeof(hdr)) {
-		err = EMSGSIZE;
-		goto bad;
-	}
-	m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
-	hdr.opcode = letoh16(hdr.opcode);
-
-	/* only allows CMD packets to be sent */
-	if (hdr.type != HCI_CMD_PKT) {
-		err = EINVAL;
-		goto bad;
-	}
-
-	/* validates packet length */
-	if (m->m_pkthdr.len != sizeof(hdr) + hdr.length) {
-		err = EMSGSIZE;
-		goto bad;
-	}
-
-	/* finds destination */
-	unit = hci_unit_lookup(addr);
-	if (unit == NULL) {
-		err = ENETDOWN;
-		goto bad;
-	}
-
-	/* security checks for unprivileged users */
-	if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
-	    && hci_security_check_opcode(unit, hdr.opcode) != hdr.length) {
-		err = EPERM;
-		goto bad;
-	}
-
-	/* makes a copy for precious to keep */
-	m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
-	if (m0 == NULL) {
-		err = ENOMEM;
-		goto bad;
-	}
-	sbappendrecord(&pcb->hp_socket->so_snd.sb, m0);
-	M_SETCTX(m, pcb->hp_socket);	/* enable drop callback */
-
-	DPRINTFN(2, "(%s) opcode (%03x|%04x)\n",
-		device_get_nameunit(unit->hci_dev),
-		HCI_OGF(hdr.opcode), HCI_OCF(hdr.opcode));
-
-	/* Sendss it */
-	if (unit->hci_num_cmd_pkts == 0)
-		IF_ENQUEUE(&unit->hci_cmdwait, m);
-	else
-		hci_output_cmd(unit, m);
-
-	return 0;
-
-bad:
-	DPRINTF("packet (%d bytes) not sent (error %d)\n",
-	    m->m_pkthdr.len, err);
-	if (m) m_freem(m);
-	return err;
-}
-
-/*
- * Implementation of usrreqs.
- *
- * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
- *	 will sofree() it when we return.
- */
-static void
-hci_sabort(netmsg_t msg)
-{
-	/* struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;	*/
-
-	soisdisconnected(msg->abort.base.nm_so);
-	hci_sdetach(msg);
-	/* msg now invalid */
-}
-
-static void
-hci_sdetach(netmsg_t msg)
-{
-	struct socket *so = msg->detach.base.nm_so;
-	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	int error;
-
-	if (pcb == NULL) {
-		error = EINVAL;
-	} else {
-		if (so->so_snd.ssb_mb != NULL)
-			hci_cmdwait_flush(so);
-
-		so->so_pcb = NULL;
-		sofree(so);		/* remove pcb ref */
-
-		LIST_REMOVE(pcb, hp_next);
-		kfree(pcb, M_PCB);
-		error = 0;
-	}
-	lwkt_replymsg(&msg->detach.base.lmsg, error);
-}
-
-static void
-hci_sdisconnect(netmsg_t msg)
-{
-	struct socket *so = msg->disconnect.base.nm_so;
-	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	int error;
-
-	if (pcb) {
-		bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY);
-		/*
-		 * XXX We cannot call soisdisconnected() here, as it sets
-		 * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem is that
-		 * soisconnected() does not clear these and if you try to
-		 * reconnect this socket (which is permitted) you get a
-		 * broken pipe when you try to write any data.
-		 */
-		soclrstate(so, SS_ISCONNECTED);
-		error = 0;
-	} else {
-		error = EINVAL;
-	}
-	lwkt_replymsg(&msg->disconnect.base.lmsg, error);
-}
-
-static void
-hci_scontrol(netmsg_t msg)
-{
-	int error;
-
-	error = hci_ioctl(msg->control.nm_cmd,
-			  (void *)msg->control.nm_data,
-			  NULL);
-	lwkt_replymsg(&msg->control.base.lmsg, error);
-}
-
-static void
-hci_sattach(netmsg_t msg)
-{
-	struct socket *so = msg->attach.base.nm_so;
-	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	int error;
-
-	if (pcb) {
-		error = EINVAL;
-		goto out;
-	}
-
-	error = soreserve(so, hci_sendspace, hci_recvspace,NULL);
-	if (error)
-		goto out;
-
-	pcb = kmalloc(sizeof *pcb, M_PCB, M_NOWAIT | M_ZERO);
-	if (pcb == NULL) {
-		error = ENOMEM;
-		goto out;
-	}
-
-	soreference(so);
-	so->so_pcb = pcb;
-	pcb->hp_socket = so;
-
-	if (curproc == NULL || priv_check(curthread, PRIV_ROOT) == 0)
-		pcb->hp_flags |= HCI_PRIVILEGED;
-
-	/*
-	 * Set default user filter. By default, socket only passes
-	 * Command_Complete and Command_Status Events.
-	 */
-	hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter);
-	hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter);
-	hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter);
-
-	crit_enter();
-	LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next);
-	crit_exit();
-	error = 0;
-out:
-	lwkt_replymsg(&msg->attach.base.lmsg, error);
-}
-
-static void
-hci_sbind(netmsg_t msg)
-{
-	struct socket *so = msg->bind.base.nm_so;
-	struct sockaddr *nam = msg->bind.nm_nam;
-	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	struct sockaddr_bt *sa;
-	int error;
-
-	KKASSERT(nam != NULL);
-	sa = (struct sockaddr_bt *)nam;
-
-	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
-		error = EINVAL;
-		goto out;
-	}
-
-	if (sa->bt_family != AF_BLUETOOTH) {
-		error = EAFNOSUPPORT;
-		goto out;
-	}
-
-	bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr);
-
-	if (bdaddr_any(&sa->bt_bdaddr))
-		pcb->hp_flags |= HCI_PROMISCUOUS;
-	else
-		pcb->hp_flags &= ~HCI_PROMISCUOUS;
-	error = 0;
-out:
-	lwkt_replymsg(&msg->bind.base.lmsg, error);
-}
-
-static void
-hci_sconnect(netmsg_t msg)
-{
-	struct socket *so = msg->connect.base.nm_so;
-	struct sockaddr *nam = msg->connect.nm_nam;
-	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	struct sockaddr_bt *sa;
-	int error;
-
-	KKASSERT(nam != NULL);
-	sa = (struct sockaddr_bt *)nam;
-
-	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
-		error = EINVAL;
-		goto out;
-	}
-
-	if (sa->bt_family != AF_BLUETOOTH) {
-		error =  EAFNOSUPPORT;
-		goto out;
-	}
-
-	if (hci_unit_lookup(&sa->bt_bdaddr) == NULL) {
-		error = EADDRNOTAVAIL;
-		goto out;
-	}
-	bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr);
-	soisconnected(so);
-	error = 0;
-out:
-	lwkt_replymsg(&msg->connect.base.lmsg, error);
-}
-
-static void
-hci_speeraddr(netmsg_t msg)
-{
-	struct socket *so = msg->peeraddr.base.nm_so;
-	struct sockaddr **nam = msg->peeraddr.nm_nam;
-	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	struct sockaddr_bt *sa;
-
-	KKASSERT(nam != NULL);
-	sa = (struct sockaddr_bt *)nam;
-
-	memset(sa, 0, sizeof(struct sockaddr_bt));
-	sa->bt_len = sizeof(struct sockaddr_bt);
-	sa->bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr);
-
-	lwkt_replymsg(&msg->connect.base.lmsg, 0);
-}
-
-static void
-hci_ssockaddr(netmsg_t msg)
-{
-	struct socket *so = msg->sockaddr.base.nm_so;
-	struct sockaddr **nam = msg->sockaddr.nm_nam;
-	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	struct sockaddr_bt *sa;
-
-	KKASSERT(nam != NULL);
-	sa = (struct sockaddr_bt *)nam;
-
-	memset(sa, 0, sizeof(struct sockaddr_bt));
-	sa->bt_len = sizeof(struct sockaddr_bt);
-	sa->bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr);
-
-	lwkt_replymsg(&msg->connect.base.lmsg, 0);
-}
-
-static void
-hci_sshutdown(netmsg_t msg)
-{
-	struct socket *so = msg->shutdown.base.nm_so;
-
-	socantsendmore(so);
-	lwkt_replymsg(&msg->connect.base.lmsg, 0);
-}
-
-static void
-hci_ssend(netmsg_t msg)
-{
-	struct socket *so = msg->send.base.nm_so;
-	struct mbuf *m = msg->send.nm_m;
-	struct sockaddr *addr = msg->send.nm_addr;
-	struct mbuf *control = msg->send.nm_control;
-	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	struct sockaddr_bt *sa;
-	int error;
-
-	sa = NULL;
-	if (addr) {
-		sa = (struct sockaddr_bt *)addr;
-
-		if (sa->bt_len != sizeof(struct sockaddr_bt)) {
-			error = EINVAL;
-			goto out;
-		}
-
-		if (sa->bt_family != AF_BLUETOOTH) {
-			error = EAFNOSUPPORT;
-			goto out;
-		}
-	}
-
-	/* have no use for this */
-	if (control) {
-		m_freem(control);
-		control = NULL;
-	}
-	error = hci_send(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr));
-	m = NULL;
-
-out:
-	if (m)
-		m_freem(m);
-	if (control)
-		m_freem(control);
-	lwkt_replymsg(&msg->send.base.lmsg, error);
-}
-
-/*
- * get/set socket options
- */
-void
-hci_ctloutput(netmsg_t msg)
-{
-	struct socket *so = msg->ctloutput.base.nm_so;
-	struct sockopt *sopt = msg->ctloutput.nm_sopt;
-	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	int idir = 0;
-	int error = 0;
-
-#ifdef notyet			/* XXX */
-	DPRINTFN(2, "req %s\n", prcorequests[req]);
-#endif
-
-	if (pcb == NULL) {
-		error = EINVAL;
-		goto out;
-	}
-
-	if (sopt->sopt_level != BTPROTO_HCI) {
-		error = ENOPROTOOPT;
-		goto out;
-	}
-
-	switch(sopt->sopt_dir) {
-	case PRCO_GETOPT:
-		switch (sopt->sopt_name) {
-		case SO_HCI_EVT_FILTER:
-			soopt_from_kbuf(sopt, &pcb->hp_efilter,
-			    sizeof(struct hci_filter));
-			break;
-
-		case SO_HCI_PKT_FILTER:
-                        soopt_from_kbuf(sopt, &pcb->hp_pfilter,
-			    sizeof(struct hci_filter));
-			break;
-
-		case SO_HCI_DIRECTION:
-			if (pcb->hp_flags & HCI_DIRECTION)
-				idir = 1;
-			else
-				idir = 0;
-			soopt_from_kbuf(sopt, &idir, sizeof(int));
-			break;
-
-		default:
-			error = ENOPROTOOPT;
-			break;
-		}
-		break;
-
-	case PRCO_SETOPT:
-		switch (sopt->sopt_name) {
-		case SO_HCI_EVT_FILTER:	/* set event filter */
-			error = soopt_to_kbuf(sopt, &pcb->hp_efilter,
-			    sizeof(struct hci_filter),
-			    sizeof(struct hci_filter));
-			break;
-
-		case SO_HCI_PKT_FILTER:	/* set packet filter */
-			error = soopt_to_kbuf(sopt, &pcb->hp_pfilter,
-					      sizeof(struct hci_filter),
-					      sizeof(struct hci_filter));
-			break;
-
-		case SO_HCI_DIRECTION:	/* request direction ctl messages */
-			error = soopt_to_kbuf(sopt, &idir, sizeof(int),
-					      sizeof(int));
-			if (error)
-				break;
-			if (idir)
-				pcb->hp_flags |= HCI_DIRECTION;
-			else
-				pcb->hp_flags &= ~HCI_DIRECTION;
-			break;
-
-		default:
-			error = ENOPROTOOPT;
-			break;
-		}
-		break;
-
-	default:
-		error = ENOPROTOOPT;
-		break;
-	}
-out:
-	lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
-}
-
-/*
- * HCI mbuf tap routine
- *
- * copy packets to any raw HCI sockets that wish (and are
- * permitted) to see them
- */
-void
-hci_mtap(struct mbuf *m, struct hci_unit *unit)
-{
-	struct hci_pcb *pcb;
-	struct mbuf *m0, *ctlmsg, **ctl;
-	struct sockaddr_bt sa;
-	uint8_t type;
-	uint8_t event;
-	uint16_t opcode;
-
-	KKASSERT(m->m_len >= sizeof(type));
-
-	type = *mtod(m, uint8_t *);
-
-	memset(&sa, 0, sizeof(sa));
-	sa.bt_len = sizeof(struct sockaddr_bt);
-	sa.bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr);
-
-	LIST_FOREACH(pcb, &hci_pcb, hp_next) {
-		/*
-		 * filter according to source address
-		 */
-		if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0
-		    && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0)
-			continue;
-
-		/*
-		 * filter according to packet type filter
-		 */
-		if (hci_filter_test(type, &pcb->hp_pfilter) == 0)
-			continue;
-
-		/*
-		 * filter according to event/security filters
-		 */
-		switch(type) {
-		case HCI_EVENT_PKT:
-			KKASSERT(m->m_len >= sizeof(hci_event_hdr_t));
-
-			event = mtod(m, hci_event_hdr_t *)->event;
-
-			if (hci_filter_test(event, &pcb->hp_efilter) == 0)
-				continue;
-
-			if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
-			    && hci_security_check_event(event) == -1)
-				continue;
-			break;
-
-		case HCI_CMD_PKT:
-			KKASSERT(m->m_len >= sizeof(hci_cmd_hdr_t));
-
-			opcode = letoh16(mtod(m, hci_cmd_hdr_t *)->opcode);
-
-			if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
-			    && hci_security_check_opcode(NULL, opcode) == -1)
-				continue;
-			break;
-
-		case HCI_ACL_DATA_PKT:
-		case HCI_SCO_DATA_PKT:
-		default:
-			if ((pcb->hp_flags & HCI_PRIVILEGED) == 0)
-				continue;
-
-			break;
-		}
-
-		/*
-		 * create control messages
-		 */
-		ctlmsg = NULL;
-		ctl = &ctlmsg;
-		if (pcb->hp_flags & HCI_DIRECTION) {
-			int dir = m->m_flags & IFF_LINK0 ? 1 : 0;
-
-			*ctl = sbcreatecontrol((void *)&dir, sizeof(dir),
-			    SCM_HCI_DIRECTION, BTPROTO_HCI);
-
-			if (*ctl != NULL)
-				ctl = &((*ctl)->m_next);
-		}
-
-		/*
-		 * copy to socket
-		 */
-		m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
-		if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv.sb,
-				(struct sockaddr *)&sa, m0, ctlmsg)) {
-			sorwakeup(pcb->hp_socket);
-		} else {
-			m_freem(ctlmsg);
-			m_freem(m0);
-		}
-	}
-}
-
-struct pr_usrreqs hci_usrreqs = {
-        .pru_abort = hci_sabort,
-        .pru_accept = pr_generic_notsupp,
-        .pru_attach = hci_sattach,
-        .pru_bind = hci_sbind,
-        .pru_connect = hci_sconnect,
-        .pru_connect2 = pr_generic_notsupp,
-        .pru_control = hci_scontrol,
-        .pru_detach = hci_sdetach,
-        .pru_disconnect = hci_sdisconnect,
-        .pru_listen = pr_generic_notsupp,
-        .pru_peeraddr = hci_speeraddr,
-        .pru_rcvd = pr_generic_notsupp,
-        .pru_rcvoob = pr_generic_notsupp,
-        .pru_send = hci_ssend,
-        .pru_sense = pru_sense_null,
-        .pru_shutdown = hci_sshutdown,
-        .pru_sockaddr = hci_ssockaddr,
-        .pru_sosend = sosend,
-        .pru_soreceive = soreceive
-};
diff --git a/sys/netbt/hci_unit.c b/sys/netbt/hci_unit.c
deleted file mode 100644
index 3c547be0f0..0000000000
--- a/sys/netbt/hci_unit.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/* $OpenBSD: src/sys/netbt/hci_unit.c,v 1.8 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: hci_unit.c,v 1.9 2007/12/30 18:26:42 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/conf.h>
-#include <sys/device.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/queue.h>
-#include <sys/systm.h>
-#include <sys/endian.h>
-#include <sys/bus.h>
-
-#include <net/netisr.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-
-struct hci_unit_list hci_unit_list = TAILQ_HEAD_INITIALIZER(hci_unit_list);
-
-/*
- * HCI Input Queue max lengths.
- */
-int hci_eventq_max = 20;
-int hci_aclrxq_max = 50;
-int hci_scorxq_max = 50;
-int hci_cmdwait_max = 50;
-int hci_scodone_max = 50;
-
-/*
- * This is the default minimum command set supported by older
- * devices. Anything conforming to 1.2 spec or later will get
- * updated during init.
- */
-static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = {
-	0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe,
-	0x07, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-/*
- * bluetooth unit functions
- */
-
-struct hci_unit *
-hci_attach(const struct hci_if *hci_if, device_t dev, uint16_t flags)
-{
-	struct hci_unit *unit;
-
-	KKASSERT(dev != NULL);
-	KKASSERT(hci_if->enable != NULL);
-	KKASSERT(hci_if->disable != NULL);
-	KKASSERT(hci_if->output_cmd != NULL);
-	KKASSERT(hci_if->output_acl != NULL);
-	KKASSERT(hci_if->output_sco != NULL);
-	KKASSERT(hci_if->get_stats != NULL);
-
-	unit = kmalloc(sizeof(struct hci_unit), M_BLUETOOTH, M_ZERO | M_WAITOK);
-	KKASSERT(unit != NULL);
-
-	unit->hci_dev = dev;
-	unit->hci_if = hci_if;
-	unit->hci_flags = flags;
-
-	lockinit(&unit->hci_devlock, "HCI device lock", 0, 0);
-
-	unit->hci_eventq.ifq_maxlen = hci_eventq_max;
-	unit->hci_aclrxq.ifq_maxlen = hci_aclrxq_max;
-	unit->hci_scorxq.ifq_maxlen = hci_scorxq_max;
-	unit->hci_cmdwait.ifq_maxlen = hci_cmdwait_max;
-	unit->hci_scodone.ifq_maxlen = hci_scodone_max;
-
-	TAILQ_INIT(&unit->hci_links);
-	LIST_INIT(&unit->hci_memos);
-
-	crit_enter();
-	TAILQ_INSERT_TAIL(&hci_unit_list, unit, hci_next);
-	crit_exit();
-
-	return unit;
-}
-
-void
-hci_detach(struct hci_unit *unit)
-{
-	crit_enter();
-	hci_disable(unit);
-
-	TAILQ_REMOVE(&hci_unit_list, unit, hci_next);
-	crit_exit();
-
-	kfree(unit, M_BLUETOOTH);
-}
-
-int
-hci_enable(struct hci_unit *unit)
-{
-	int err;
-
-	/*
-	 * Bluetooth spec says that a device can accept one
-	 * command on power up until they send a Command Status
-	 * or Command Complete event with more information, but
-	 * it seems that some devices cant and prefer to send a
-	 * No-op Command Status packet when they are ready.
-	 */
-	unit->hci_num_cmd_pkts = (unit->hci_flags & BTF_POWER_UP_NOOP) ? 0 : 1;
-	unit->hci_num_acl_pkts = 0;
-	unit->hci_num_sco_pkts = 0;
-
-	/*
-	 * only allow the basic packet types until
-	 * the features report is in
-	 */
-	unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
-	unit->hci_packet_type = unit->hci_acl_mask;
-
-	memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE);
-	err = (*unit->hci_if->enable)(unit->hci_dev);
-	if (err)
-		goto bad1;
-
-	unit->hci_flags |= BTF_RUNNING;
-
-	/*
-	 * Reset the device, this will trigger initialisation
-	 * and wake us up.
-	 */
-	crit_enter(); 
- 	unit->hci_flags |= BTF_INIT;
-	crit_exit();
-
-	err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0);
-	if (err)
-		goto bad2;
-		
-	while (unit->hci_flags & BTF_INIT) {
-		err = tsleep(unit, PCATCH, "hciena", 5 * hz);
-		if (err)
-			goto bad2;
-			
-		/* XXX
-		 * "What If", while we were sleeping, the device
-		 * was removed and detached? Ho Hum.
-		 */
-	}
-
-#if 0 /* not yet */
-	/*
-	 * Attach Bluetooth Device Hub
-	 */
-	unit->hci_bthub = NULL;
-	
-	unit->hci_bthub = device_add_child(unit->hci_softc, "bthub", -1);
-	if (!unit->hci_bthub) {
-		device_printf(unit->hci_softc, "Device creation failed\n");
-		goto bad2;
-	}
-
-	DPRINTFN(10, "%s is added as child to %s\n",
-	    device_get_nameunit(unit->hci_bthub),
-	    device_get_nameunit(unit->hci_softc));
-
-	device_set_desc(unit->hci_bthub,"Bluetooth Device Hub");
-
-	device_set_ivars(unit->hci_bthub, &unit->hci_bdaddr);
-
-	device_probe_and_attach(unit->hci_bthub);
-#endif
-	return 0;
-
-bad2:
-	(*unit->hci_if->disable)(unit->hci_dev);
-	unit->hci_flags &= ~BTF_RUNNING;
-
-bad1:
-	return err;
-}
-
-void
-hci_disable(struct hci_unit *unit)
-{
-	struct hci_link *link, *next;
-	struct hci_memo *memo;
-	int acl;
-
-#if 0 /* not yet */
-	if (unit->hci_bthub) {
-		device_delete_child(unit->hci_softc, unit->hci_bthub);
-		unit->hci_bthub = NULL;
-	}
-#endif
-
-	(*unit->hci_if->disable)(unit->hci_dev);
-	unit->hci_flags &= ~BTF_RUNNING;
-
-	/*
-	 * close down any links, take care to close SCO first since
-	 * they may depend on ACL links.
-	 */
-	for (acl = 0 ; acl < 2 ; acl++) {
-		next = TAILQ_FIRST(&unit->hci_links);
-		while ((link = next) != NULL) {
-			next = TAILQ_NEXT(link, hl_next);
-			if (acl || link->hl_type != HCI_LINK_ACL)
-				hci_link_free(link, ECONNABORTED);
-		}
-	}
-
-	while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
-		hci_memo_free(memo);
-
-	/* (no need to hold hci_devlock, the driver is disabled) */
-
-	IF_DRAIN(&unit->hci_eventq);
-	unit->hci_eventqlen = 0;
-
-	IF_DRAIN(&unit->hci_aclrxq);
-	unit->hci_aclrxqlen = 0;
-
-	IF_DRAIN(&unit->hci_scorxq);
-	unit->hci_scorxqlen = 0;
-
-	IF_DRAIN(&unit->hci_cmdwait);
-	IF_DRAIN(&unit->hci_scodone);
-}
-
-struct hci_unit *
-hci_unit_lookup(bdaddr_t *addr)
-{
-	struct hci_unit *unit;
-
-	TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
-		if ((unit->hci_flags & BTF_UP) == 0)
-			continue;
-
-		if (bdaddr_same(&unit->hci_bdaddr, addr))
-			break;
-	}
-
-	return unit;
-}
-
-/*
- * construct and queue a HCI command packet
- */
-int
-hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
-{
-	struct mbuf *m;
-	hci_cmd_hdr_t *p;
-
-	KKASSERT(unit != NULL);
-
-	m = m_gethdr(M_NOWAIT, MT_DATA);
-	if (m == NULL)
-		return ENOMEM;
-
-	p = mtod(m, hci_cmd_hdr_t *);
-	p->type = HCI_CMD_PKT;
-	p->opcode = htole16(opcode);
-	p->length = len;
-	m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
-	M_SETCTX(m, NULL);	/* XXX is this needed? */
-
-	if (len) {
-		KKASSERT(buf != NULL);
-
-		m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
-		if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
-			m_freem(m);
-			return ENOMEM;
-		}
-	}
-
-	DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n",
-		device_get_nameunit(unit->hci_dev),
-		HCI_OGF(opcode), HCI_OCF(opcode));
-
-	/* and send it on */
-	if (unit->hci_num_cmd_pkts == 0)
-		IF_ENQUEUE(&unit->hci_cmdwait, m);
-	else
-		hci_output_cmd(unit, m);
-
-	return 0;
-}
-
-/*
- * Incoming packet processing. Since the code is single threaded
- * in any case (IPL_SOFTNET), we handle it all in one interrupt function
- * picking our way through more important packets first so that hopefully
- * we will never get clogged up with bulk data.
- */
-void
-hci_intr(void *arg)
-{
-	struct hci_unit *unit = arg;
-	struct mbuf *m;
-
-another:
-	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
-
-	if (unit->hci_eventqlen > 0) {
-		IF_DEQUEUE(&unit->hci_eventq, m);
-		unit->hci_eventqlen--;
-		lockmgr(&unit->hci_devlock, LK_RELEASE);
-
-		KKASSERT(m != NULL);
-
-		DPRINTFN(10, "(%s) recv event, len = %d\n",
-		    device_get_nameunit(unit->hci_dev), m->m_pkthdr.len);
-
-		m->m_flags |= IFF_LINK0;	/* mark incoming packet */
-		hci_mtap(m, unit);
-		hci_event(m, unit);
-
-		goto another;
-	}
-
-	if (unit->hci_scorxqlen > 0) {
-		IF_DEQUEUE(&unit->hci_scorxq, m);
-		unit->hci_scorxqlen--;
-		lockmgr(&unit->hci_devlock, LK_RELEASE);
-		KKASSERT(m != NULL);
-
-		DPRINTFN(10, "(%s) recv SCO, len = %d\n",
-		    device_get_nameunit(unit->hci_dev), m->m_pkthdr.len);
-
-		m->m_flags |= IFF_LINK0;	/* mark incoming packet */
-		hci_mtap(m, unit);
-		hci_sco_recv(m, unit);
-		
-		goto another;
-	}
-
-	if (unit->hci_aclrxqlen > 0) {
-		IF_DEQUEUE(&unit->hci_aclrxq, m);
-		unit->hci_aclrxqlen--;
-		lockmgr(&unit->hci_devlock, LK_RELEASE);
-
-		KKASSERT(m != NULL);
-		
-		DPRINTFN(10, "(%s) recv ACL, len = %d\n",
-		    device_get_nameunit(unit->hci_dev), m->m_pkthdr.len);
-
-		m->m_flags |= IFF_LINK0;	/* mark incoming packet */
-		hci_mtap(m, unit);
-		hci_acl_recv(m, unit);
-
-		goto another;
-	}
-
-	IF_DEQUEUE(&unit->hci_scodone, m);
-	if (m != NULL) {
-		struct hci_link *link;
-		lockmgr(&unit->hci_devlock, LK_RELEASE);
-
-		DPRINTFN(11, "(%s) complete SCO\n",
-		    device_get_nameunit(unit->hci_dev));
-
-		TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
-			if (link == M_GETCTX(m, struct hci_link *)) {
-				hci_sco_complete(link, 1);
-				break;
-			}
-		}
-
-		unit->hci_num_sco_pkts++;
-		m_freem(m);
-
-		goto another;
-	}
-
-	lockmgr(&unit->hci_devlock, LK_RELEASE);
-
-	DPRINTFN(10, "done\n");
-}
-
-/**********************************************************************
- *
- * IO routines
- *
- * input & complete routines will be called from device drivers,
- * possibly in interrupt context. We return success or failure to
- * enable proper accounting but we own the mbuf.
- */
-
-int
-hci_input_event(struct hci_unit *unit, struct mbuf *m)
-{
-	int rv;
-
-	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
-
-	if (unit->hci_eventqlen > hci_eventq_max) {
-		DPRINTF("(%s) dropped event packet.\n",
-		    device_get_nameunit(unit->hci_dev));
-		m_freem(m);
-		rv = 0;
-	} else {
-		unit->hci_eventqlen++;
-		IF_ENQUEUE(&unit->hci_eventq, m);
-		netisr_queue(NETISR_BLUETOOTH, m);
-		rv = 1;
-	}
-	lockmgr(&unit->hci_devlock, LK_RELEASE);
-
-	return rv;
-}
-
-int
-hci_input_acl(struct hci_unit *unit, struct mbuf *m)
-{
-	int rv;
-
-	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
-	if (unit->hci_aclrxqlen > hci_aclrxq_max) {
-		DPRINTF("(%s) dropped ACL packet.\n",
-		    device_get_nameunit(unit->hci_dev));
-		m_freem(m);
-		rv = 0;
-	} else {
-		unit->hci_aclrxqlen++;
-		IF_ENQUEUE(&unit->hci_aclrxq, m);
-		netisr_queue(NETISR_BLUETOOTH, m);
-		rv = 1;
-	}
-	lockmgr(&unit->hci_devlock, LK_RELEASE);
-
-	return rv;
-}
-
-int
-hci_input_sco(struct hci_unit *unit, struct mbuf *m)
-{
-	int rv;
-
-	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
-	if (unit->hci_scorxqlen > hci_scorxq_max) {
-		DPRINTF("(%s) dropped SCO packet.\n",
-		    device_get_nameunit(unit->hci_dev));
-		m_freem(m);
-		rv = 0;
-	} else {
-		unit->hci_scorxqlen++;
-		IF_ENQUEUE(&unit->hci_scorxq, m);
-		netisr_queue(NETISR_BLUETOOTH, m);
-		rv = 1;
-	}
-	lockmgr(&unit->hci_devlock, LK_RELEASE);
-
-	return rv;
-}
-
-void
-hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
-{
-	void *arg;
-
-	hci_mtap(m, unit);
-
-	DPRINTFN(10, "(%s) num_cmd_pkts=%d\n",
-	    device_get_nameunit(unit->hci_dev), unit->hci_num_cmd_pkts);
-
-	unit->hci_num_cmd_pkts--;
-
-	/*
-	 * If context is set, this was from a HCI raw socket
-	 * and a record needs to be dropped from the sockbuf.
-	 */
-	arg = M_GETCTX(m, void *);
-	if (arg != NULL)
-		hci_drop(arg);
-
-	(*unit->hci_if->output_cmd)(unit->hci_dev, m);
-}
-
-void
-hci_output_acl(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_mtap(m, unit);
-
-	DPRINTFN(10, "(%s) num_acl_pkts=%d\n",
-	    device_get_nameunit(unit->hci_dev), unit->hci_num_acl_pkts);
-
-	unit->hci_num_acl_pkts--;
-
-	(*unit->hci_if->output_acl)(unit->hci_dev, m);
-}
-
-void
-hci_output_sco(struct hci_unit *unit, struct mbuf *m)
-{
-	hci_mtap(m, unit);
-
-	DPRINTFN(10, "(%s) num_sco_pkts=%d\n",
-	    device_get_nameunit(unit->hci_dev), unit->hci_num_sco_pkts);
-
-	unit->hci_num_sco_pkts--;
-
-	(*unit->hci_if->output_sco)(unit->hci_dev, m);
-}
-
-int
-hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
-{
-	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
-	IF_ENQUEUE(&unit->hci_scodone, m);
-	netisr_queue(NETISR_BLUETOOTH,m);
-	lockmgr(&unit->hci_devlock, LK_RELEASE);
-
-	return 1;
-}
diff --git a/sys/netbt/l2cap.h b/sys/netbt/l2cap.h
deleted file mode 100644
index fe2286a48e..0000000000
--- a/sys/netbt/l2cap.h
+++ /dev/null
@@ -1,493 +0,0 @@
-/* $DragonFly: src/sys/netbt/l2cap.h,v 1.2 2008/03/18 13:41:42 hasso Exp $ */
-/* $OpenBSD: src/sys/netbt/l2cap.h,v 1.5 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: l2cap.h,v 1.6 2007/11/03 17:20:17 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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) Maksim Yevmenkin <m_evmenkin@yahoo.com>
- * 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.
- *
- * $Id: l2cap.h,v 1.6 2007/11/03 17:20:17 plunky Exp $
- * $FreeBSD: src/sys/netgraph/bluetooth/include/l2cap.h,v 1.4 2005/08/31 18:13:23 emax Exp $
- */
-
-/*
- * This file contains everything that application needs to know about
- * Link Layer Control and Adaptation Protocol (L2CAP). All information
- * was obtained from Bluetooth Specification Books (v1.1 and up)
- *
- * This file can be included by both kernel and userland applications.
- */
-
-#ifndef _NETBT_L2CAP_H_
-#define _NETBT_L2CAP_H_
-
-#include <sys/types.h>
-
-/**************************************************************************
- **************************************************************************
- **                   Common defines and types (L2CAP)
- **************************************************************************
- **************************************************************************/
-
-/*
- * Channel IDs are assigned per machine. So the total number of channels that
- * a machine can have open at the same time is 0xffff - 0x0040 = 0xffbf (65471).
- * This number does not depend on number of HCI connections.
- */
-
-#define L2CAP_NULL_CID			0x0000	/* DO NOT USE THIS CID */
-#define L2CAP_SIGNAL_CID		0x0001	/* signaling channel ID */
-#define L2CAP_CLT_CID			0x0002	/* connectionless channel ID */
-	/* 0x0003 - 0x003f Reserved */
-#define L2CAP_FIRST_CID			0x0040	/* dynamically alloc. (start) */
-#define L2CAP_LAST_CID			0xffff	/* dynamically alloc. (end) */
-
-/* L2CAP MTU */
-#define L2CAP_MTU_MINIMUM		48
-#define L2CAP_MTU_DEFAULT		672
-#define L2CAP_MTU_MAXIMUM		0xffff
-
-/* L2CAP flush and link timeouts */
-#define L2CAP_FLUSH_TIMO_DEFAULT	0xffff /* always retransmit */
-#define L2CAP_LINK_TIMO_DEFAULT		0xffff
-
-/* L2CAP Command Reject reasons */
-#define L2CAP_REJ_NOT_UNDERSTOOD	0x0000
-#define L2CAP_REJ_MTU_EXCEEDED		0x0001
-#define L2CAP_REJ_INVALID_CID		0x0002
-/* 0x0003 - 0xffff - reserved for future use */
-
-/* Protocol/Service Multiplexor (PSM) values */
-#define L2CAP_PSM_ANY			0x0000	/* Any/Invalid PSM */
-#define L2CAP_PSM_SDP			0x0001	/* Service Discovery Protocol */
-#define L2CAP_PSM_RFCOMM		0x0003	/* RFCOMM protocol */
-#define L2CAP_PSM_TCP			0x0005	/* Telephony Control Protocol */
-#define L2CAP_PSM_TCS			0x0007	/* TCS cordless */
-#define L2CAP_PSM_BNEP			0x000f	/* Bluetooth Network */
-						/*	Encapsulation Protocol*/
-#define L2CAP_PSM_HID_CNTL		0x0011	/* HID Control */
-#define L2CAP_PSM_HID_INTR		0x0013	/* HID Interrupt */
-#define L2CAP_PSM_ESDP			0x0015	/* Extended Service */
-						/*	Discovery Profile */
-#define L2CAP_PSM_AVCTP			0x0017	/* Audio/Visual Control */
-						/*	Transport Protocol */
-#define L2CAP_PSM_AVDTP			0x0019	/* Audio/Visual Distribution */
-						/*	Transport Protocol */
-/* 0x0019 - 0x1000 - reserved for future use */
-
-#define L2CAP_PSM_INVALID(psm)		(((psm) & 0x0101) != 0x0001)
-
-/* L2CAP Connection response command result codes */
-#define L2CAP_SUCCESS			0x0000
-#define L2CAP_PENDING			0x0001
-#define L2CAP_PSM_NOT_SUPPORTED		0x0002
-#define L2CAP_SECURITY_BLOCK		0x0003
-#define L2CAP_NO_RESOURCES		0x0004
-#define L2CAP_TIMEOUT			0xeeee
-#define L2CAP_UNKNOWN			0xffff
-/* 0x0005 - 0xffff - reserved for future use */
-
-/* L2CAP Connection response status codes */
-#define L2CAP_NO_INFO			0x0000
-#define L2CAP_AUTH_PENDING		0x0001
-#define L2CAP_AUTZ_PENDING		0x0002
-/* 0x0003 - 0xffff - reserved for future use */
-
-/* L2CAP Configuration response result codes */
-#define L2CAP_UNACCEPTABLE_PARAMS	0x0001
-#define L2CAP_REJECT			0x0002
-#define L2CAP_UNKNOWN_OPTION		0x0003
-/* 0x0003 - 0xffff - reserved for future use */
-
-/* L2CAP Configuration options */
-#define L2CAP_OPT_CFLAG_BIT		0x0001
-#define L2CAP_OPT_CFLAG(flags)		((flags) & L2CAP_OPT_CFLAG_BIT)
-#define L2CAP_OPT_HINT_BIT		0x80
-#define L2CAP_OPT_HINT(type)		((type) & L2CAP_OPT_HINT_BIT)
-#define L2CAP_OPT_HINT_MASK		0x7f
-#define L2CAP_OPT_MTU			0x01
-#define L2CAP_OPT_MTU_SIZE		sizeof(uint16_t)
-#define L2CAP_OPT_FLUSH_TIMO		0x02
-#define L2CAP_OPT_FLUSH_TIMO_SIZE	sizeof(uint16_t)
-#define L2CAP_OPT_QOS			0x03
-#define L2CAP_OPT_QOS_SIZE		sizeof(l2cap_qos_t)
-#define L2CAP_OPT_RFC			0x04
-#define L2CAP_OPT_RFC_SIZE		sizeof(l2cap_rfc_t)
-/* 0x05 - 0xff - reserved for future use */
-
-/* L2CAP Information request type codes */
-#define L2CAP_CONNLESS_MTU		0x0001
-#define L2CAP_EXTENDED_FEATURES		0x0002
-/* 0x0003 - 0xffff - reserved for future use */
-
-/* L2CAP Information response codes */
-#define L2CAP_NOT_SUPPORTED		0x0001
-/* 0x0002 - 0xffff - reserved for future use */
-
-/* L2CAP Quality of Service option */
-typedef struct {
-	uint8_t  flags;			/* reserved for future use */
-	uint8_t  service_type;		/* service type */
-	uint32_t token_rate;		/* bytes per second */
-	uint32_t token_bucket_size;	/* bytes */
-	uint32_t peak_bandwidth;	/* bytes per second */
-	uint32_t latency;		/* microseconds */
-	uint32_t delay_variation;	/* microseconds */
-} __attribute__ ((__packed__)) l2cap_qos_t;
-
-/* L2CAP QoS type */
-#define L2CAP_QOS_NO_TRAFFIC	0x00
-#define L2CAP_QOS_BEST_EFFORT	0x01       /* (default) */
-#define L2CAP_QOS_GUARANTEED	0x02
-/* 0x03 - 0xff - reserved for future use */
-
-/* L2CAP Retransmission & Flow Control option */
-typedef struct {
-	uint8_t	mode;		   /* RFC mode */
-	uint8_t	window_size;	   /* bytes */
-	uint8_t	max_transmit;	   /* max retransmissions */
-	uint16_t	retransmit_timo;   /* milliseconds */
-	uint16_t	monitor_timo;	   /* milliseconds */
-	uint16_t	max_pdu_size;	   /* bytes */
-} __attribute__ ((__packed__)) l2cap_rfc_t;
-
-/* L2CAP RFC mode */
-#define L2CAP_RFC_BASIC		0x00	   /* (default) */
-#define L2CAP_RFC_RETRANSMIT	0x01
-#define L2CAP_RFC_FLOW		0x02
-/* 0x03 - 0xff - reserved for future use */
-
-/**************************************************************************
- **************************************************************************
- **                 Link level defines, headers and types
- **************************************************************************
- **************************************************************************/
-
-/* L2CAP header */
-typedef struct {
-	uint16_t	length;	/* payload size */
-	uint16_t	dcid;	/* destination channel ID */
-} __attribute__ ((__packed__)) l2cap_hdr_t;
-
-/* L2CAP ConnectionLess Traffic		(dcid == L2CAP_CLT_CID) */
-typedef struct {
-	uint16_t	psm; /* Protocol/Service Multiplexor */
-} __attribute__ ((__packed__)) l2cap_clt_hdr_t;
-
-#define L2CAP_CLT_MTU_MAXIMUM \
-	(L2CAP_MTU_MAXIMUM - sizeof(l2cap_clt_hdr_t))
-
-/* L2CAP Command header			(dcid == L2CAP_SIGNAL_CID) */
-typedef struct {
-	uint8_t	code;   /* command OpCode */
-	uint8_t	ident;  /* identifier to match request and response */
-	uint16_t	length; /* command parameters length */
-} __attribute__ ((__packed__)) l2cap_cmd_hdr_t;
-
-/* L2CAP Command Reject */
-#define L2CAP_COMMAND_REJ			0x01
-typedef struct {
-	uint16_t	reason; /* reason to reject command */
-	uint16_t	data[2];/* optional data */
-} __attribute__ ((__packed__)) l2cap_cmd_rej_cp;
-
-/* L2CAP Connection Request */
-#define L2CAP_CONNECT_REQ			0x02
-typedef struct {
-	uint16_t	psm;  /* Protocol/Service Multiplexor (PSM) */
-	uint16_t	scid; /* source channel ID */
-} __attribute__ ((__packed__)) l2cap_con_req_cp;
-
-/* L2CAP Connection Response */
-#define L2CAP_CONNECT_RSP			0x03
-typedef struct {
-	uint16_t	dcid;   /* destination channel ID */
-	uint16_t	scid;   /* source channel ID */
-	uint16_t	result; /* 0x00 - success */
-	uint16_t	status; /* more info if result != 0x00 */
-} __attribute__ ((__packed__)) l2cap_con_rsp_cp;
-
-/* L2CAP Configuration Request */
-#define L2CAP_CONFIG_REQ			0x04
-typedef struct {
-	uint16_t	dcid;  /* destination channel ID */
-	uint16_t	flags; /* flags */
-/*	uint8_t	options[] --  options */
-} __attribute__ ((__packed__)) l2cap_cfg_req_cp;
-
-/* L2CAP Configuration Response */
-#define L2CAP_CONFIG_RSP			0x05
-typedef struct {
-	uint16_t	scid;   /* source channel ID */
-	uint16_t	flags;  /* flags */
-	uint16_t	result; /* 0x00 - success */
-/*	uint8_t	options[] -- options */
-} __attribute__ ((__packed__)) l2cap_cfg_rsp_cp;
-
-/* L2CAP configuration option */
-typedef struct {
-	uint8_t	type;
-	uint8_t	length;
-/*	uint8_t	value[] -- option value (depends on type) */
-} __attribute__ ((__packed__)) l2cap_cfg_opt_t;
-
-/* L2CAP configuration option value */
-typedef union {
-	uint16_t		mtu;		/* L2CAP_OPT_MTU */
-	uint16_t		flush_timo;	/* L2CAP_OPT_FLUSH_TIMO */
-	l2cap_qos_t		qos;		/* L2CAP_OPT_QOS */
-	l2cap_rfc_t		rfc;		/* L2CAP_OPT_RFC */
-} l2cap_cfg_opt_val_t;
-
-/* L2CAP Disconnect Request */
-#define L2CAP_DISCONNECT_REQ			0x06
-typedef struct {
-	uint16_t	dcid; /* destination channel ID */
-	uint16_t	scid; /* source channel ID */
-} __attribute__ ((__packed__)) l2cap_discon_req_cp;
-
-/* L2CAP Disconnect Response */
-#define L2CAP_DISCONNECT_RSP			0x07
-typedef l2cap_discon_req_cp	l2cap_discon_rsp_cp;
-
-/* L2CAP Echo Request */
-#define L2CAP_ECHO_REQ				0x08
-/* No command parameters, only optional data */
-
-/* L2CAP Echo Response */
-#define L2CAP_ECHO_RSP				0x09
-#define L2CAP_MAX_ECHO_SIZE \
-	(L2CAP_MTU_MAXIMUM - sizeof(l2cap_cmd_hdr_t))
-/* No command parameters, only optional data */
-
-/* L2CAP Information Request */
-#define L2CAP_INFO_REQ				0x0a
-typedef struct {
-	uint16_t	type; /* requested information type */
-} __attribute__ ((__packed__)) l2cap_info_req_cp;
-
-/* L2CAP Information Response */
-#define L2CAP_INFO_RSP				0x0b
-typedef struct {
-	uint16_t	type;   /* requested information type */
-	uint16_t	result; /* 0x00 - success */
-/*	uint8_t	info[]  -- info data (depends on type)
- *
- * L2CAP_CONNLESS_MTU - 2 bytes connectionless MTU
- */
-} __attribute__ ((__packed__)) l2cap_info_rsp_cp;
-
-typedef union {
-	/* L2CAP_CONNLESS_MTU */
-	struct {
-		uint16_t	mtu;
-	} __attribute__ ((__packed__)) mtu;
-} l2cap_info_rsp_data_t;
-
-/**************************************************************************
- **************************************************************************
- **		L2CAP Socket Definitions
- **************************************************************************
- **************************************************************************/
-
-/* Socket options */
-#define SO_L2CAP_IMTU		1	/* incoming MTU */
-#define SO_L2CAP_OMTU		2	/* outgoing MTU */
-#define SO_L2CAP_IQOS		3	/* incoming QoS */
-#define SO_L2CAP_OQOS		4	/* outgoing QoS */
-#define SO_L2CAP_FLUSH		5	/* flush timeout */
-#define SO_L2CAP_LM		6	/* link mode */
-
-/* L2CAP link mode flags */
-#define L2CAP_LM_AUTH		(1<<0)	/* want authentication */
-#define L2CAP_LM_ENCRYPT	(1<<1)	/* want encryption */
-#define L2CAP_LM_SECURE		(1<<2)	/* want secured link */
-
-#ifdef _KERNEL
-#include <vm/vm_zone.h>
-
-#include <net/if.h>		/* for struct ifqueue */
-
-LIST_HEAD(l2cap_channel_list, l2cap_channel);
-
-/* global variables */
-extern struct l2cap_channel_list l2cap_active_list;
-extern struct l2cap_channel_list l2cap_listen_list;
-extern vm_zone_t l2cap_pdu_pool;
-extern vm_zone_t l2cap_req_pool;
-extern const l2cap_qos_t l2cap_default_qos;
-
-/* sysctl variables */
-extern int l2cap_response_timeout;
-extern int l2cap_response_extended_timeout;
-extern int l2cap_sendspace, l2cap_recvspace;
-
-/*
- * L2CAP Channel
- */
-struct l2cap_channel {
-	struct hci_link		*lc_link;	/* ACL connection (down) */
-	uint16_t		 lc_state;	/* channel state */
-	uint16_t		 lc_flags;	/* channel flags */
-	uint8_t			 lc_ident;	/* cached request id */
-
-	uint16_t		 lc_lcid;	/* local channel ID */
-	struct sockaddr_bt	 lc_laddr;	/* local address */
-
-	uint16_t		 lc_rcid;	/* remote channel ID */
-	struct sockaddr_bt	 lc_raddr;	/* remote address */
-
-	int			 lc_mode;	/* link mode */
-	uint16_t		 lc_imtu;	/* incoming mtu */
-	uint16_t		 lc_omtu;	/* outgoing mtu */
-	uint16_t		 lc_flush;	/* flush timeout */
-	l2cap_qos_t		 lc_iqos;	/* incoming QoS flow control */
-	l2cap_qos_t		 lc_oqos;	/* outgoing Qos flow control */
-
-	uint8_t			 lc_pending;	/* num of pending PDUs */
-	struct ifqueue		 lc_txq;	/* transmit queue */
-
-	const struct btproto	*lc_proto;	/* upper layer callbacks */
-	void			*lc_upper;	/* upper layer argument */
-
-	LIST_ENTRY(l2cap_channel)lc_ncid;	/* next channel (ascending CID) */
-};
-
-/* l2cap_channel state */
-#define L2CAP_CLOSED			0 /* closed */
-#define L2CAP_WAIT_SEND_CONNECT_REQ	1 /* waiting to send connect request */
-#define L2CAP_WAIT_RECV_CONNECT_RSP	2 /* waiting to recv connect response */
-#define L2CAP_WAIT_SEND_CONNECT_RSP	3 /* waiting to send connect response */
-#define L2CAP_WAIT_CONFIG		4 /* waiting for configuration */
-#define L2CAP_OPEN			5 /* user data transfer state */
-#define L2CAP_WAIT_DISCONNECT		6 /* have sent disconnect request */
-
-/* l2cap_channel flags */
-#define L2CAP_SHUTDOWN		(1<<0)	/* channel is closing */
-#define L2CAP_WAIT_CONFIG_REQ	(1<<1)	/* waiting for config request */
-#define L2CAP_WAIT_CONFIG_RSP	(1<<2)	/* waiting for config response */
-
-/*
- * L2CAP Request
- */
-struct l2cap_req {
-	struct hci_link		*lr_link;	/* ACL connection */
-	struct l2cap_channel	*lr_chan;	/* channel pointer */
-	uint8_t			 lr_code;	/* request code */
-	uint8_t			 lr_id;		/* request id */
-	struct callout		 lr_rtx;	/* response timer */
-	TAILQ_ENTRY(l2cap_req)	 lr_next;	/* next request on link */
-};
-
-/*
- * L2CAP Protocol Data Unit
- */
-struct l2cap_pdu {
-	struct l2cap_channel	*lp_chan;	/* PDU owner */
-	struct ifqueue		 lp_data;	/* PDU data */
-	TAILQ_ENTRY(l2cap_pdu)	 lp_next;	/* next PDU on link */
-	int			 lp_pending;	/* # of fragments pending */
-};
-
-/*
- * L2CAP function prototypes
- */
-
-extern struct pr_usrreqs l2cap_usrreqs;
-struct socket;
-struct mbuf;
-union netmsg;
-
-/* l2cap_lower.c */
-void l2cap_close(struct l2cap_channel *, int);
-void l2cap_recv_frame(struct mbuf *, struct hci_link *);
-int l2cap_start(struct l2cap_channel *);
-
-/* l2cap_misc.c */
-void l2cap_init(void);
-int l2cap_setmode(struct l2cap_channel *);
-int l2cap_cid_alloc(struct l2cap_channel *);
-struct l2cap_channel *l2cap_cid_lookup(uint16_t);
-int l2cap_request_alloc(struct l2cap_channel *, uint8_t);
-struct l2cap_req *l2cap_request_lookup(struct hci_link *, uint8_t);
-void l2cap_request_free(struct l2cap_req *);
-void l2cap_rtx(void *);
-
-/* l2cap_signal.c */
-void l2cap_recv_signal(struct mbuf *, struct hci_link *);
-int l2cap_send_connect_req(struct l2cap_channel *);
-int l2cap_send_config_req(struct l2cap_channel *);
-int l2cap_send_disconnect_req(struct l2cap_channel *);
-int l2cap_send_connect_rsp(struct hci_link *, uint8_t, uint16_t, uint16_t, uint16_t);
-
-/* l2cap_socket.c */
-int l2cap_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *);
-void l2cap_ctloutput(union netmsg *);
-
-/* l2cap_upper.c */
-int l2cap_attach(struct l2cap_channel **, const struct btproto *, void *);
-int l2cap_bind(struct l2cap_channel *, struct sockaddr_bt *);
-int l2cap_sockaddr(struct l2cap_channel *, struct sockaddr_bt *);
-int l2cap_connect(struct l2cap_channel *, struct sockaddr_bt *);
-int l2cap_peeraddr(struct l2cap_channel *, struct sockaddr_bt *);
-int l2cap_disconnect(struct l2cap_channel *, int);
-int l2cap_detach(struct l2cap_channel **);
-int l2cap_listen(struct l2cap_channel *);
-int l2cap_send(struct l2cap_channel *, struct mbuf *);
-int l2cap_setopt(struct l2cap_channel *, int, void *);
-int l2cap_setopt2(struct l2cap_channel *, int, struct socket *, struct sockopt *);
-int l2cap_getopt(struct l2cap_channel *, int, void *);
-
-#endif	/* _KERNEL */
-
-#endif	/* _NETBT_L2CAP_H_ */
diff --git a/sys/netbt/l2cap_lower.c b/sys/netbt/l2cap_lower.c
deleted file mode 100644
index 99d14a9b66..0000000000
--- a/sys/netbt/l2cap_lower.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/* $DragonFly: src/sys/netbt/l2cap_lower.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */
-/* $OpenBSD: src/sys/netbt/l2cap_lower.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: l2cap_lower.c,v 1.7 2007/11/10 23:12:23 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/queue.h>
-#include <sys/systm.h>
-#include <sys/endian.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-
-/****************************************************************************
- *
- *	L2CAP Channel Lower Layer interface
- */
-
-/*
- * L2CAP channel is disconnected, could be:
- *
- * HCI layer received "Disconnect Complete" event for ACL link
- * some Request timed out
- * Config failed
- * Other end reported invalid CID
- * Normal disconnection
- * Change link mode failed
- */
-void
-l2cap_close(struct l2cap_channel *chan, int err)
-{
-	struct l2cap_pdu *pdu;
-	struct l2cap_req *req, *n;
-
-	if (chan->lc_state == L2CAP_CLOSED)
-		return;
-
-	/*
-	 * Since any potential PDU could be half sent we just let it go,
-	 * but disassociate ourselves from it as links deal with ownerless
-	 * PDU's in any case.  We could try harder to flush unsent packets
-	 * but maybe its better to leave them in the queue?
-	 */
-	TAILQ_FOREACH(pdu, &chan->lc_link->hl_txq, lp_next) {
-		if (pdu->lp_chan == chan)
-			pdu->lp_chan = NULL;
-	}
-
-	/*
-	 * and clear any outstanding requests..
-	 */
-	req = TAILQ_FIRST(&chan->lc_link->hl_reqs);
-	while (req != NULL) {
-		n = TAILQ_NEXT(req, lr_next);
-		if (req->lr_chan == chan)
-			l2cap_request_free(req);
-
-		req = n;
-	}
-
-	chan->lc_pending = 0;
-	chan->lc_state = L2CAP_CLOSED;
-	hci_acl_close(chan->lc_link, err);
-	chan->lc_link = NULL;
-
-	(*chan->lc_proto->disconnected)(chan->lc_upper, err);
-}
-
-/*
- * Process incoming L2CAP frame from ACL link. We take off the B-Frame
- * header (which is present in all packets), verify the data length
- * and distribute the rest of the frame to the relevant channel
- * handler.
- */
-void
-l2cap_recv_frame(struct mbuf *m, struct hci_link *link)
-{
-	struct l2cap_channel *chan;
-	l2cap_hdr_t hdr;
-
-	m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
-	m_adj(m, sizeof(hdr));
-
-	hdr.length = letoh16(hdr.length);
-	hdr.dcid = letoh16(hdr.dcid);
-
-	DPRINTFN(5, "(%s) received packet (%d bytes)\n",
-		    device_get_nameunit(link->hl_unit->hci_dev), hdr.length);
-
-	if (hdr.length != m->m_pkthdr.len)
-		goto failed;
-
-	if (hdr.dcid == L2CAP_SIGNAL_CID) {
-		l2cap_recv_signal(m, link);
-		return;
-	}
-
-	if (hdr.dcid == L2CAP_CLT_CID) {
-		m_freem(m);	/* TODO */
-		return;
-	}
-
-	chan = l2cap_cid_lookup(hdr.dcid);
-	if (chan != NULL && chan->lc_link == link
-	    && chan->lc_state == L2CAP_OPEN) {
-		(*chan->lc_proto->input)(chan->lc_upper, m);
-		return;
-	}
-
-	DPRINTF("(%s) dropping %d L2CAP data bytes for unknown CID #%d\n",
-		device_get_nameunit(link->hl_unit->hci_dev), hdr.length,
-		hdr.dcid);
-
-failed:
-	m_freem(m);
-}
-
-/*
- * Start another L2CAP packet on its way. This is called from l2cap_send
- * (when no PDU is pending) and hci_acl_start (when PDU has been placed on
- * device queue). Thus we can have more than one PDU waiting at the device
- * if space is available but no single channel will hog the link.
- */
-int
-l2cap_start(struct l2cap_channel *chan)
-{
-	struct mbuf *m;
-	int err = 0;
-
-	if (chan->lc_state != L2CAP_OPEN)
-		return 0;
-
-	if (IF_QEMPTY(&chan->lc_txq)) {
-		DPRINTFN(5, "no data, pending = %d\n", chan->lc_pending);
-		/*
-		 * If we are just waiting for the queue to flush
-		 * and it has, we may disconnect..
-		 */
-		if (chan->lc_flags & L2CAP_SHUTDOWN
-		    && chan->lc_pending == 0) {
-			chan->lc_state = L2CAP_WAIT_DISCONNECT;
-			err = l2cap_send_disconnect_req(chan);
-			if (err)
-				l2cap_close(chan, err);
-		}
-
-		return err;
-	}
-
-	/*
-	 * We could check QoS/RFC mode here and optionally not send
-	 * the packet if we are not ready for any reason
-	 *
-	 * Also to support flush timeout then we might want to start
-	 * the timer going? (would need to keep some kind of record
-	 * of packets sent, possibly change it so that we allocate
-	 * the l2cap_pdu and fragment the packet, then hand it down
-	 * and get it back when its completed). Hm.
-	 */
-
-	IF_DEQUEUE(&chan->lc_txq, m);
-
-	KKASSERT(chan->lc_link != NULL);
-	KKASSERT(m != NULL);
-
-	DPRINTFN(5, "CID #%d sending packet (%d bytes)\n",
-		chan->lc_lcid, m->m_pkthdr.len);
-
-	chan->lc_pending++;
-	return hci_acl_send(m, chan->lc_link, chan);
-}
diff --git a/sys/netbt/l2cap_misc.c b/sys/netbt/l2cap_misc.c
deleted file mode 100644
index 0b63067cc2..0000000000
--- a/sys/netbt/l2cap_misc.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* $OpenBSD: src/sys/netbt/l2cap_misc.c,v 1.3 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: l2cap_misc.c,v 1.5 2007/11/03 17:20:17 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/queue.h>
-#include <sys/systm.h>
-#include <net/if.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-
-struct l2cap_channel_list
-	l2cap_active_list = LIST_HEAD_INITIALIZER(l2cap_active_list);
-struct l2cap_channel_list
-	l2cap_listen_list = LIST_HEAD_INITIALIZER(l2cap_listen_list);
-
-vm_zone_t l2cap_req_pool;
-vm_zone_t l2cap_pdu_pool;
-
-const l2cap_qos_t l2cap_default_qos = {
-	0,			/* flags */
-	L2CAP_QOS_BEST_EFFORT,	/* service type */
-	0x00000000,		/* token rate */
-	0x00000000,		/* token bucket size */
-	0x00000000,		/* peak bandwidth */
-	0xffffffff,		/* latency */
-	0xffffffff		/* delay variation */
-};
-
-/*
- * L2CAP request timeouts
- */
-int l2cap_response_timeout = 30;		/* seconds */
-int l2cap_response_extended_timeout = 180;	/* seconds */
-
-void
-l2cap_init(void)
-{
-}
-
-/*
- * Set Link Mode on channel
- */
-int
-l2cap_setmode(struct l2cap_channel *chan)
-{
-	KKASSERT(chan != NULL);
-	KKASSERT(chan->lc_link != NULL);
-
-	DPRINTF("(%s) CID #%d, auth %s, encrypt %s, secure %s\n",
-	    device_get_nameunit(chan->lc_link->hl_unit->hci_dev), chan->lc_lcid,
-	    (chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"),
-	    (chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"),
-	    (chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no"));
-
-	if (chan->lc_mode & L2CAP_LM_AUTH)
-		chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ;
-
-	if (chan->lc_mode & L2CAP_LM_ENCRYPT)
-		chan->lc_link->hl_flags |= HCI_LINK_ENCRYPT_REQ;
-
-	if (chan->lc_mode & L2CAP_LM_SECURE)
-		chan->lc_link->hl_flags |= HCI_LINK_SECURE_REQ;
-
-	return hci_acl_setmode(chan->lc_link);
-}
-
-/*
- * Allocate a new Request structure & ID and set the timer going
- */
-int
-l2cap_request_alloc(struct l2cap_channel *chan, uint8_t code)
-{
-	struct hci_link *link = chan->lc_link;
-	struct l2cap_req *req;
-	int next_id;
-
-	if (link == NULL)
-		return ENETDOWN;
-
-	/* find next ID (0 is not allowed) */
-	next_id = link->hl_lastid + 1;
-	if (next_id > 0xff)
-		next_id = 1;
-
-	/* Ouroboros check */
-	req = TAILQ_FIRST(&link->hl_reqs);
-	if (req && req->lr_id == next_id)
-		return ENFILE;
-
-	req = zalloc(l2cap_req_pool);
-	if (req == NULL)
-		return ENOMEM;
-
-	req->lr_id = link->hl_lastid = next_id;
-
-	req->lr_code = code;
-	req->lr_chan = chan;
-	req->lr_link = link;
-
-	callout_init(&req->lr_rtx);
-	callout_reset(&req->lr_rtx, l2cap_response_timeout * hz,
-	    l2cap_rtx, req);
-
-	TAILQ_INSERT_TAIL(&link->hl_reqs, req, lr_next);
-
-	return 0;
-}
-
-/*
- * Find a running request for this link
- */
-struct l2cap_req *
-l2cap_request_lookup(struct hci_link *link, uint8_t id)
-{
-	struct l2cap_req *req;
-
-	TAILQ_FOREACH(req, &link->hl_reqs, lr_next) {
-		if (req->lr_id == id)
-			return req;
-	}
-
-	return NULL;
-}
-
-/*
- * Halt and free a request
- */
-void
-l2cap_request_free(struct l2cap_req *req)
-{
-	struct hci_link *link = req->lr_link;
-
-	callout_stop(&req->lr_rtx);
-	if (callout_active(&req->lr_rtx))
-		return;
-
-	TAILQ_REMOVE(&link->hl_reqs, req, lr_next);
-	zfree(l2cap_req_pool, req);
-}
-
-/*
- * Response Timeout eXpired
- *
- * No response to our request, so deal with it as best we can.
- *
- * XXX should try again at least with ertx?
- */
-void
-l2cap_rtx(void *arg)
-{
-	struct l2cap_req *req = arg;
-	struct l2cap_channel *chan;
-
-	chan = req->lr_chan;
-	l2cap_request_free(req);
-
-	DPRINTF("cid %d, ident %d\n", (chan ? chan->lc_lcid : 0), req->lr_id);
-
-	if (chan && chan->lc_state != L2CAP_CLOSED)
-		l2cap_close(chan, ETIMEDOUT);
-
-}
-
-/*
- * Allocate next available CID to channel. We keep a single
- * ordered list of channels, so find the first gap.
- *
- * If this turns out to be not enough (!), could use a
- * list per HCI unit..
- */
-int
-l2cap_cid_alloc(struct l2cap_channel *chan)
-{
-	struct l2cap_channel *used, *prev = NULL;
-	uint16_t cid = L2CAP_FIRST_CID;
-
-	if (chan->lc_lcid != L2CAP_NULL_CID || chan->lc_state != L2CAP_CLOSED)
-		return EISCONN;
-
-	LIST_FOREACH(used, &l2cap_active_list, lc_ncid) {
-		if (used->lc_lcid > cid)
-			break;	/* found our gap */
-
-		KKASSERT(used->lc_lcid == cid);
-		cid++;
-
-		if (cid == L2CAP_LAST_CID)
-			return ENFILE;
-
-		prev = used;	/* for insert after */
-	}
-
-	chan->lc_lcid = cid;
-
-	if (prev)
-		LIST_INSERT_AFTER(prev, chan, lc_ncid);
-	else
-		LIST_INSERT_HEAD(&l2cap_active_list, chan, lc_ncid);
-
-	return 0;
-}
-
-/*
- * Find channel with CID
- */
-struct l2cap_channel *
-l2cap_cid_lookup(uint16_t cid)
-{
-	struct l2cap_channel *chan;
-
-	LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
-		if (chan->lc_lcid == cid)
-			return chan;
-
-		if (chan->lc_lcid > cid)
-			return NULL;
-	}
-
-	return NULL;
-}
diff --git a/sys/netbt/l2cap_signal.c b/sys/netbt/l2cap_signal.c
deleted file mode 100644
index 149385fb49..0000000000
--- a/sys/netbt/l2cap_signal.c
+++ /dev/null
@@ -1,1154 +0,0 @@
-/* $OpenBSD: src/sys/netbt/l2cap_signal.c,v 1.3 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: l2cap_signal.c,v 1.9 2007/11/10 23:12:23 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>	/* for M_NOWAIT */
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/queue.h>
-#include <sys/systm.h>
-#include <sys/endian.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-
-/*******************************************************************************
- *
- *	L2CAP Signal processing
- */
-
-static void l2cap_recv_command_rej(struct mbuf *, struct hci_link *);
-static void l2cap_recv_connect_req(struct mbuf *, struct hci_link *);
-static void l2cap_recv_connect_rsp(struct mbuf *, struct hci_link *);
-static void l2cap_recv_config_req(struct mbuf *, struct hci_link *);
-static void l2cap_recv_config_rsp(struct mbuf *, struct hci_link *);
-static void l2cap_recv_disconnect_req(struct mbuf *, struct hci_link *);
-static void l2cap_recv_disconnect_rsp(struct mbuf *, struct hci_link *);
-static void l2cap_recv_info_req(struct mbuf *, struct hci_link *);
-static int l2cap_send_signal(struct hci_link *, uint8_t, uint8_t, uint16_t, void *);
-static int l2cap_send_command_rej(struct hci_link *, uint8_t, uint16_t, ...);
-
-/*
- * process incoming signal packets (CID 0x0001). Can contain multiple
- * requests/responses.
- */
-void
-l2cap_recv_signal(struct mbuf *m, struct hci_link *link)
-{
-	l2cap_cmd_hdr_t cmd;
-
-	for(;;) {
-		if (m->m_pkthdr.len == 0)
-			goto finish;
-
-		if (m->m_pkthdr.len < sizeof(cmd))
-			goto reject;
-
-		m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd);
-		cmd.length = letoh16(cmd.length);
-
-		if (m->m_pkthdr.len < sizeof(cmd) + cmd.length)
-			goto reject;
-
-		DPRINTFN(2, "(%s) code %d, ident %d, len %d\n",
-			device_get_nameunit(link->hl_unit->hci_dev),
-			cmd.code, cmd.ident, cmd.length);
-
-		switch (cmd.code) {
-		case L2CAP_COMMAND_REJ:
-			if (cmd.length > sizeof(l2cap_cmd_rej_cp))
-				goto finish;
-
-			l2cap_recv_command_rej(m, link);
-			break;
-
-		case L2CAP_CONNECT_REQ:
-			if (cmd.length != sizeof(l2cap_con_req_cp))
-				goto reject;
-
-			l2cap_recv_connect_req(m, link);
-			break;
-
-		case L2CAP_CONNECT_RSP:
-			if (cmd.length != sizeof(l2cap_con_rsp_cp))
-				goto finish;
-
-			l2cap_recv_connect_rsp(m, link);
-			break;
-
-		case L2CAP_CONFIG_REQ:
-			l2cap_recv_config_req(m, link);
-			break;
-
-		case L2CAP_CONFIG_RSP:
-			l2cap_recv_config_rsp(m, link);
-			break;
-
-		case L2CAP_DISCONNECT_REQ:
-			if (cmd.length != sizeof(l2cap_discon_req_cp))
-				goto reject;
-
-			l2cap_recv_disconnect_req(m, link);
-			break;
-
-		case L2CAP_DISCONNECT_RSP:
-			if (cmd.length != sizeof(l2cap_discon_rsp_cp))
-				goto finish;
-
-			l2cap_recv_disconnect_rsp(m, link);
-			break;
-
-		case L2CAP_ECHO_REQ:
-			m_adj(m, sizeof(cmd) + cmd.length);
-			l2cap_send_signal(link, L2CAP_ECHO_RSP, cmd.ident,
-					0, NULL);
-			break;
-
-		case L2CAP_ECHO_RSP:
-			m_adj(m, sizeof(cmd) + cmd.length);
-			break;
-
-		case L2CAP_INFO_REQ:
-			if (cmd.length != sizeof(l2cap_info_req_cp))
-				goto reject;
-
-			l2cap_recv_info_req(m, link);
-			break;
-
-		case L2CAP_INFO_RSP:
-			m_adj(m, sizeof(cmd) + cmd.length);
-			break;
-
-		default:
-			goto reject;
-		}
-	}
-
-#ifdef DIAGNOSTIC
-	panic("impossible!");
-#endif
-
-reject:
-	l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_NOT_UNDERSTOOD);
-finish:
-	m_freem(m);
-}
-
-/*
- * Process Received Command Reject. For now we dont try to recover gracefully
- * from this, it probably means that the link is garbled or the other end is
- * insufficiently capable of handling normal traffic. (not *my* fault, no way!)
- */
-static void
-l2cap_recv_command_rej(struct mbuf *m, struct hci_link *link)
-{
-	struct l2cap_req *req;
-	struct l2cap_channel *chan;
-	l2cap_cmd_hdr_t cmd;
-	l2cap_cmd_rej_cp cp;
-
-	m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd);
-	m_adj(m, sizeof(cmd));
-
-	cmd.length = letoh16(cmd.length);
-
-	m_copydata(m, 0, cmd.length, (caddr_t)&cp);
-	m_adj(m, cmd.length);
-
-	req = l2cap_request_lookup(link, cmd.ident);
-	if (req == NULL)
-		return;
-
-	switch (letoh16(cp.reason)) {
-	case L2CAP_REJ_NOT_UNDERSTOOD:
-		/*
-		 * I dont know what to do, just move up the timeout
-		 */
-		callout_reset(&req->lr_rtx,0,l2cap_rtx,req);
-		break;
-
-	case L2CAP_REJ_MTU_EXCEEDED:
-		/*
-		 * I didnt send any commands over L2CAP_MTU_MINIMUM size, but..
-		 *
-		 * XXX maybe we should resend this, instead?
-		 */
-		link->hl_mtu = letoh16(cp.data[0]);
-		callout_reset(&req->lr_rtx,0,l2cap_rtx,req);
-		break;
-
-	case L2CAP_REJ_INVALID_CID:
-		/*
-		 * Well, if they dont have such a channel then our channel is
-		 * most likely closed. Make it so.
-		 */
-		chan = req->lr_chan;
-		l2cap_request_free(req);
-		if (chan != NULL && chan->lc_state != L2CAP_CLOSED)
-			l2cap_close(chan, ECONNABORTED);
-
-		break;
-
-	default:
-		UNKNOWN(letoh16(cp.reason));
-		break;
-	}
-}
-
-/*
- * Process Received Connect Request. Find listening channel matching
- * psm & addr and ask upper layer for a new channel.
- */
-static void
-l2cap_recv_connect_req(struct mbuf *m, struct hci_link *link)
-{
-	struct sockaddr_bt laddr, raddr;
-	struct l2cap_channel *chan, *new;
-	l2cap_cmd_hdr_t cmd;
-	l2cap_con_req_cp cp;
-	int err;
-
-	/* extract cmd */
-	m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd);
-	m_adj(m, sizeof(cmd));
-
-	/* extract request */
-	m_copydata(m, 0, sizeof(cp), (caddr_t)&cp);
-	m_adj(m, sizeof(cp));
-
-	cp.scid = letoh16(cp.scid);
-	cp.psm = letoh16(cp.psm);
-
-	memset(&laddr, 0, sizeof(struct sockaddr_bt));
-	laddr.bt_len = sizeof(struct sockaddr_bt);
-	laddr.bt_family = AF_BLUETOOTH;
-	laddr.bt_psm = cp.psm;
-	bdaddr_copy(&laddr.bt_bdaddr, &link->hl_unit->hci_bdaddr);
-
-	memset(&raddr, 0, sizeof(struct sockaddr_bt));
-	raddr.bt_len = sizeof(struct sockaddr_bt);
-	raddr.bt_family = AF_BLUETOOTH;
-	raddr.bt_psm = cp.psm;
-	bdaddr_copy(&raddr.bt_bdaddr, &link->hl_bdaddr);
-
-	LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) {
-		if (chan->lc_laddr.bt_psm != laddr.bt_psm
-		    && chan->lc_laddr.bt_psm != L2CAP_PSM_ANY)
-			continue;
-
-		if (!bdaddr_same(&laddr.bt_bdaddr, &chan->lc_laddr.bt_bdaddr)
-		    && bdaddr_any(&chan->lc_laddr.bt_bdaddr) == 0)
-			continue;
-
-		new= (*chan->lc_proto->newconn)(chan->lc_upper, &laddr, &raddr);
-		if (new == NULL)
-			continue;
-
-		err = l2cap_cid_alloc(new);
-		if (err) {
-			l2cap_send_connect_rsp(link, cmd.ident,
-						0, cp.scid,
-						L2CAP_NO_RESOURCES);
-
-			(*new->lc_proto->disconnected)(new->lc_upper, err);
-			return;
-		}
-
-		new->lc_link = hci_acl_open(link->hl_unit, &link->hl_bdaddr);
-		KKASSERT(new->lc_link == link);
-
-		new->lc_rcid = cp.scid;
-		new->lc_ident = cmd.ident;
-
-		memcpy(&new->lc_laddr, &laddr, sizeof(struct sockaddr_bt));
-		memcpy(&new->lc_raddr, &raddr, sizeof(struct sockaddr_bt));
-
-		new->lc_mode = chan->lc_mode;
-
-		err = l2cap_setmode(new);
-		if (err == EINPROGRESS) {
-			new->lc_state = L2CAP_WAIT_SEND_CONNECT_RSP;
-			(*new->lc_proto->connecting)(new->lc_upper);
-			return;
-		}
-		if (err) {
-			new->lc_state = L2CAP_CLOSED;
-			hci_acl_close(link, err);
-			new->lc_link = NULL;
-
-			l2cap_send_connect_rsp(link, cmd.ident,
-						0, cp.scid,
-						L2CAP_NO_RESOURCES);
-
-			(*new->lc_proto->disconnected)(new->lc_upper, err);
-			return;
-		}
-
-		err = l2cap_send_connect_rsp(link, cmd.ident,
-					      new->lc_lcid, new->lc_rcid,
-					      L2CAP_SUCCESS);
-		if (err) {
-			l2cap_close(new, err);
-			return;
-		}
-
-		new->lc_state = L2CAP_WAIT_CONFIG;
-		new->lc_flags |= (L2CAP_WAIT_CONFIG_REQ | L2CAP_WAIT_CONFIG_RSP);
-		err = l2cap_send_config_req(new);
-		if (err)
-			l2cap_close(new, err);
-
-		return;
-	}
-
-	l2cap_send_connect_rsp(link, cmd.ident,
-				0, cp.scid,
-				L2CAP_PSM_NOT_SUPPORTED);
-}
-
-/*
- * Process Received Connect Response.
- */
-static void
-l2cap_recv_connect_rsp(struct mbuf *m, struct hci_link *link)
-{
-	l2cap_cmd_hdr_t cmd;
-	l2cap_con_rsp_cp cp;
-	struct l2cap_req *req;
-	struct l2cap_channel *chan;
-
-	m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd);
-	m_adj(m, sizeof(cmd));
-
-	m_copydata(m, 0, sizeof(cp), (caddr_t)&cp);
-	m_adj(m, sizeof(cp));
-
-	cp.scid = letoh16(cp.scid);
-	cp.dcid = letoh16(cp.dcid);
-	cp.result = letoh16(cp.result);
-
-	req = l2cap_request_lookup(link, cmd.ident);
-	if (req == NULL || req->lr_code != L2CAP_CONNECT_REQ)
-		return;
-
-	chan = req->lr_chan;
-	if (chan != NULL && chan->lc_lcid != cp.scid)
-		return;
-
-	if (chan == NULL || chan->lc_state != L2CAP_WAIT_RECV_CONNECT_RSP) {
-		l2cap_request_free(req);
-		return;
-	}
-
-	switch (cp.result) {
-	case L2CAP_SUCCESS:
-		/*
-		 * Ok, at this point we have a connection to the other party. We
-		 * could indicate upstream that we are ready for business and
-		 * wait for a "Configure Channel Request" but I'm not so sure
-		 * that is required in our case - we will proceed directly to
-		 * sending our config request. We set two state bits because in
-		 * the config state we are waiting for requests and responses.
-		 */
-		l2cap_request_free(req);
-		chan->lc_rcid = cp.dcid;
-		chan->lc_state = L2CAP_WAIT_CONFIG;
-		chan->lc_flags |= (L2CAP_WAIT_CONFIG_REQ | L2CAP_WAIT_CONFIG_RSP);
-		l2cap_send_config_req(chan);
-		break;
-
-	case L2CAP_PENDING:
-		/* XXX dont release request, should start eRTX timeout? */
-		(*chan->lc_proto->connecting)(chan->lc_upper);
-		break;
-
-	case L2CAP_PSM_NOT_SUPPORTED:
-	case L2CAP_SECURITY_BLOCK:
-	case L2CAP_NO_RESOURCES:
-	default:
-		l2cap_request_free(req);
-		l2cap_close(chan, ECONNREFUSED);
-		break;
-	}
-}
-
-/*
- * Process Received Config Request.
- */
-static void
-l2cap_recv_config_req(struct mbuf *m, struct hci_link *link)
-{
-	uint8_t buf[L2CAP_MTU_MINIMUM];
-	l2cap_cmd_hdr_t cmd;
-	l2cap_cfg_req_cp cp;
-	l2cap_cfg_opt_t opt;
-	l2cap_cfg_opt_val_t val;
-	l2cap_cfg_rsp_cp rp;
-	struct l2cap_channel *chan;
-	int left, len;
-
-	m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd);
-	m_adj(m, sizeof(cmd));
-	left = letoh16(cmd.length);
-
-	if (left < sizeof(cp))
-		goto reject;
-
-	m_copydata(m, 0, sizeof(cp), (caddr_t)&cp);
-	m_adj(m, sizeof(cp));
-	left -= sizeof(cp);
-
-	cp.dcid = letoh16(cp.dcid);
-	cp.flags = letoh16(cp.flags);
-
-	chan = l2cap_cid_lookup(cp.dcid);
-	if (chan == NULL || chan->lc_link != link
-	    || chan->lc_state != L2CAP_WAIT_CONFIG
-	    || (chan->lc_flags & L2CAP_WAIT_CONFIG_REQ) == 0) {
-		/* XXX we should really accept reconfiguration requests */
-		l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_INVALID_CID,
-					L2CAP_NULL_CID, cp.dcid);
-		goto out;
-	}
-
-	/* ready our response packet */
-	rp.scid = htole16(chan->lc_rcid);
-	rp.flags = 0;	/* "No Continuation" */
-	rp.result = L2CAP_SUCCESS;
-	len = sizeof(rp);
-
-	/*
-	 * Process the packet. We build the return packet on the fly adding any
-	 * unacceptable parameters as we go. As we can only return one result,
-	 * unknown option takes precedence so we start our return packet anew
-	 * and ignore option values thereafter as they will be re-sent.
-	 *
-	 * Since we do not support enough options to make overflowing the min
-	 * MTU size an issue in normal use, we just reject config requests that
-	 * make that happen. This could be because options are repeated or the
-	 * packet is corrupted in some way.
-	 *
-	 * If unknown option types threaten to overflow the packet, we just
-	 * ignore them. We can deny them next time.
-	 */
-	while (left > 0) {
-		if (left < sizeof(opt))
-			goto reject;
-
-		m_copydata(m, 0, sizeof(opt), (caddr_t)&opt);
-		m_adj(m, sizeof(opt));
-		left -= sizeof(opt);
-
-		if (left < opt.length)
-			goto reject;
-
-		switch(opt.type & L2CAP_OPT_HINT_MASK) {
-		case L2CAP_OPT_MTU:
-			if (rp.result == L2CAP_UNKNOWN_OPTION)
-				break;
-
-			if (opt.length != L2CAP_OPT_MTU_SIZE)
-				goto reject;
-
-			m_copydata(m, 0, L2CAP_OPT_MTU_SIZE, (caddr_t)&val);
-			val.mtu = letoh16(val.mtu);
-
-			/*
-			 * XXX how do we know what the minimum acceptable MTU is
-			 * for a channel? Spec says some profiles have a higher
-			 * minimum but I have no way to find that out at this
-			 * juncture..
-			 */
-			if (val.mtu < L2CAP_MTU_MINIMUM) {
-				if (len + sizeof(opt) + L2CAP_OPT_MTU_SIZE > sizeof(buf))
-					goto reject;
-
-				rp.result = L2CAP_UNACCEPTABLE_PARAMS;
-				memcpy(buf + len, &opt, sizeof(opt));
-				len += sizeof(opt);
-				val.mtu = htole16(L2CAP_MTU_MINIMUM);
-				memcpy(buf + len, &val, L2CAP_OPT_MTU_SIZE);
-				len += L2CAP_OPT_MTU_SIZE;
-			} else
-				chan->lc_omtu = val.mtu;
-
-			break;
-
-		case L2CAP_OPT_FLUSH_TIMO:
-			if (rp.result == L2CAP_UNKNOWN_OPTION)
-				break;
-
-			if (opt.length != L2CAP_OPT_FLUSH_TIMO_SIZE)
-				goto reject;
-
-			/*
-			 * I think that this is informational only - he is
-			 * informing us of the flush timeout he will be using.
-			 * I dont think this affects us in any significant way,
-			 * so just ignore this value for now.
-			 */
-			break;
-
-		case L2CAP_OPT_QOS:
-			if (rp.result == L2CAP_UNKNOWN_OPTION)
-				break;
-
-			if (opt.length != L2CAP_OPT_QOS_SIZE)
-				goto reject;
-
-			m_copydata(m, 0, L2CAP_OPT_QOS_SIZE, (caddr_t)&val);
-			if (val.qos.service_type == L2CAP_QOS_NO_TRAFFIC ||
-			    val.qos.service_type == L2CAP_QOS_BEST_EFFORT)
-				/*
-				 * In accordance with the spec, we choose to
-				 * ignore the fields an provide no response.
-				 */
-				break;
-
-			if (len + sizeof(opt) + L2CAP_OPT_QOS_SIZE > sizeof(buf))
-				goto reject;
-
-			if (val.qos.service_type != L2CAP_QOS_GUARANTEED) {
-				/*
-				 * Instead of sending an "unacceptable
-				 * parameters" response, treat this as an
-				 * unknown option and include the option
-				 * value in the response.
-				 */
-				rp.result = L2CAP_UNKNOWN_OPTION;
-			} else {
-				/*
-				 * According to the spec, we must return
-				 * specific values for wild card parameters.
-				 * I don't know what to return without lying,
-				 * so return "unacceptable parameters" and
-				 * specify the preferred service type as
-				 * "Best Effort".
-				 */
-				rp.result = L2CAP_UNACCEPTABLE_PARAMS;
-				val.qos.service_type = L2CAP_QOS_BEST_EFFORT;
-			}
-
-			memcpy(buf + len, &opt, sizeof(opt));
-			len += sizeof(opt);
-			memcpy(buf + len, &val, L2CAP_OPT_QOS_SIZE);
-			len += L2CAP_OPT_QOS_SIZE;
-			break;
-
-		default:
-			/* ignore hints */
-			if (opt.type & L2CAP_OPT_HINT_BIT)
-				break;
-
-			/* unknown options supersede all else */
-			if (rp.result != L2CAP_UNKNOWN_OPTION) {
-				rp.result = L2CAP_UNKNOWN_OPTION;
-				len = sizeof(rp);
-			}
-
-			/* ignore if it doesn't fit */
-			if (len + sizeof(opt) > sizeof(buf))
-				break;
-
-			/* return unknown option type, but no data */
-			buf[len++] = opt.type;
-			buf[len++] = 0;
-			break;
-		}
-
-		m_adj(m, opt.length);
-		left -= opt.length;
-	}
-
-	rp.result = htole16(rp.result);
-	memcpy(buf, &rp, sizeof(rp));
-	l2cap_send_signal(link, L2CAP_CONFIG_RSP, cmd.ident, len, buf);
-
-	if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0
-	    && rp.result == letoh16(L2CAP_SUCCESS)) {
-
-		chan->lc_flags &= ~L2CAP_WAIT_CONFIG_REQ;
-
-		if ((chan->lc_flags & L2CAP_WAIT_CONFIG_RSP) == 0) {
-			chan->lc_state = L2CAP_OPEN;
-			/* XXX how to distinguish REconfiguration? */
-			(*chan->lc_proto->connected)(chan->lc_upper);
-		}
-	}
-	return;
-
-reject:
-	l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_NOT_UNDERSTOOD);
-out:
-	m_adj(m, left);
-}
-
-/*
- * Process Received Config Response.
- */
-static void
-l2cap_recv_config_rsp(struct mbuf *m, struct hci_link *link)
-{
-	l2cap_cmd_hdr_t cmd;
-	l2cap_cfg_rsp_cp cp;
-	l2cap_cfg_opt_t opt;
-	l2cap_cfg_opt_val_t val;
-	struct l2cap_req *req;
-	struct l2cap_channel *chan;
-	int left;
-
-	m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd);
-	m_adj(m, sizeof(cmd));
-	left = letoh16(cmd.length);
-
-	if (left < sizeof(cp))
-		goto out;
-
-	m_copydata(m, 0, sizeof(cp), (caddr_t)&cp);
-	m_adj(m, sizeof(cp));
-	left -= sizeof(cp);
-
-	cp.scid = letoh16(cp.scid);
-	cp.flags = letoh16(cp.flags);
-	cp.result = letoh16(cp.result);
-
-	req = l2cap_request_lookup(link, cmd.ident);
-	if (req == NULL || req->lr_code != L2CAP_CONFIG_REQ)
-		goto out;
-
-	chan = req->lr_chan;
-	if (chan != NULL && chan->lc_lcid != cp.scid)
-		goto out;
-
-	l2cap_request_free(req);
-
-	if (chan == NULL || chan->lc_state != L2CAP_WAIT_CONFIG
-	    || (chan->lc_flags & L2CAP_WAIT_CONFIG_RSP) == 0)
-		goto out;
-
-	if ((cp.flags & L2CAP_OPT_CFLAG_BIT)) {
-		l2cap_cfg_req_cp rp;
-
-		/*
-		 * They have more to tell us and want another ID to
-		 * use, so send an empty config request
-		 */
-		if (l2cap_request_alloc(chan, L2CAP_CONFIG_REQ))
-			goto discon;
-
-		rp.dcid = htole16(cp.scid);
-		rp.flags = 0;
-
-		if (l2cap_send_signal(link, L2CAP_CONFIG_REQ, link->hl_lastid,
-					sizeof(rp), &rp))
-			goto discon;
-	}
-
-	switch(cp.result) {
-	case L2CAP_SUCCESS:
-		/*
-		 * If continuation flag was not set, our config request was
-		 * accepted. We may have to wait for their config request to
-		 * complete, so check that but otherwise we are open
-		 *
-		 * There may be 'advisory' values in the packet but we just
-		 * ignore those..
-		 */
-		if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0) {
-			chan->lc_flags &= ~L2CAP_WAIT_CONFIG_RSP;
-
-			if ((chan->lc_flags & L2CAP_WAIT_CONFIG_REQ) == 0) {
-				chan->lc_state = L2CAP_OPEN;
-				/* XXX how to distinguish REconfiguration? */
-				(*chan->lc_proto->connected)(chan->lc_upper);
-			}
-		}
-		goto out;
-
-	case L2CAP_UNACCEPTABLE_PARAMS:
-		/*
-		 * Packet contains unacceptable parameters with preferred values
-		 */
-		while (left > 0) {
-			if (left < sizeof(opt))
-				goto discon;
-
-			m_copydata(m, 0, sizeof(opt), (caddr_t)&opt);
-			m_adj(m, sizeof(opt));
-			left -= sizeof(opt);
-
-			if (left < opt.length)
-				goto discon;
-
-			switch (opt.type) {
-			case L2CAP_OPT_MTU:
-				if (opt.length != L2CAP_OPT_MTU_SIZE)
-					goto discon;
-
-				m_copydata(m, 0, L2CAP_OPT_MTU_SIZE, (caddr_t)&val);
-				chan->lc_imtu = letoh16(val.mtu);
-				if (chan->lc_imtu < L2CAP_MTU_MINIMUM)
-					chan->lc_imtu = L2CAP_MTU_DEFAULT;
-				break;
-
-			case L2CAP_OPT_FLUSH_TIMO:
-				if (opt.length != L2CAP_OPT_FLUSH_TIMO_SIZE)
-					goto discon;
-
-				/*
-				 * Spec says: If we cannot honor proposed value,
-				 * either disconnect or try again with original
-				 * value. I can't really see why they want to
-				 * interfere with OUR flush timeout in any case
-				 * so we just punt for now.
-				 */
-				goto discon;
-
-			case L2CAP_OPT_QOS:
-				break;
-
-			default:
-				UNKNOWN(opt.type);
-				goto discon;
-			}
-
-			m_adj(m, opt.length);
-			left -= opt.length;
-		}
-
-		if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0)
-			l2cap_send_config_req(chan);	/* no state change */
-
-		goto out;
-
-	case L2CAP_REJECT:
-		goto discon;
-
-	case L2CAP_UNKNOWN_OPTION:
-		/*
-		 * Packet contains options not understood. Turn off unknown
-		 * options by setting them to default values (means they will
-		 * not be requested again).
-		 *
-		 * If our option was already off then fail (paranoia?)
-		 *
-		 * XXX Should we consider that options were set for a reason?
-		 */
-		while (left > 0) {
-			if (left < sizeof(opt))
-				goto discon;
-
-			m_copydata(m, 0, sizeof(opt), (caddr_t)&opt);
-			m_adj(m, sizeof(opt));
-			left -= sizeof(opt);
-
-			if (left < opt.length)
-				goto discon;
-
-			m_adj(m, opt.length);
-			left -= opt.length;
-
-			switch(opt.type) {
-			case L2CAP_OPT_MTU:
-				if (chan->lc_imtu == L2CAP_MTU_DEFAULT)
-					goto discon;
-
-				chan->lc_imtu = L2CAP_MTU_DEFAULT;
-				break;
-
-			case L2CAP_OPT_FLUSH_TIMO:
-				if (chan->lc_flush == L2CAP_FLUSH_TIMO_DEFAULT)
-					goto discon;
-
-				chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT;
-				break;
-
-			case L2CAP_OPT_QOS:
-				break;
-
-			default:
-				UNKNOWN(opt.type);
-				goto discon;
-			}
-		}
-
-		if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0)
-			l2cap_send_config_req(chan);	/* no state change */
-
-		goto out;
-
-	default:
-		UNKNOWN(cp.result);
-		goto discon;
-	}
-
-	DPRINTF("how did I get here!?\n");
-
-discon:
-	l2cap_send_disconnect_req(chan);
-	l2cap_close(chan, ECONNABORTED);
-
-out:
-	m_adj(m, left);
-}
-
-/*
- * Process Received Disconnect Request. We must validate scid and dcid
- * just in case but otherwise this connection is finished.
- */
-static void
-l2cap_recv_disconnect_req(struct mbuf *m, struct hci_link *link)
-{
-	l2cap_cmd_hdr_t cmd;
-	l2cap_discon_req_cp cp;
-	l2cap_discon_rsp_cp rp;
-	struct l2cap_channel *chan;
-
-	m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd);
-	m_adj(m, sizeof(cmd));
-
-	m_copydata(m, 0, sizeof(cp), (caddr_t)&cp);
-	m_adj(m, sizeof(cp));
-
-	cp.scid = letoh16(cp.scid);
-	cp.dcid = letoh16(cp.dcid);
-
-	chan = l2cap_cid_lookup(cp.dcid);
-	if (chan == NULL || chan->lc_link != link || chan->lc_rcid != cp.scid) {
-		l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_INVALID_CID,
-					cp.dcid, cp.scid);
-		return;
-	}
-
-	rp.dcid = htole16(chan->lc_lcid);
-	rp.scid = htole16(chan->lc_rcid);
-	l2cap_send_signal(link, L2CAP_DISCONNECT_RSP, cmd.ident,
-				sizeof(rp), &rp);
-
-	if (chan->lc_state != L2CAP_CLOSED)
-		l2cap_close(chan, ECONNRESET);
-}
-
-/*
- * Process Received Disconnect Response. We must validate scid and dcid but
- * unless we were waiting for this signal, ignore it.
- */
-static void
-l2cap_recv_disconnect_rsp(struct mbuf *m, struct hci_link *link)
-{
-	l2cap_cmd_hdr_t cmd;
-	l2cap_discon_rsp_cp cp;
-	struct l2cap_req *req;
-	struct l2cap_channel *chan;
-
-	m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd);
-	m_adj(m, sizeof(cmd));
-
-	m_copydata(m, 0, sizeof(cp), (caddr_t)&cp);
-	m_adj(m, sizeof(cp));
-
-	cp.scid = letoh16(cp.scid);
-	cp.dcid = letoh16(cp.dcid);
-
-	req = l2cap_request_lookup(link, cmd.ident);
-	if (req == NULL || req->lr_code != L2CAP_DISCONNECT_REQ)
-		return;
-
-	chan = req->lr_chan;
-	if (chan == NULL
-	    || chan->lc_lcid != cp.scid
-	    || chan->lc_rcid != cp.dcid)
-		return;
-
-	l2cap_request_free(req);
-
-	if (chan->lc_state != L2CAP_WAIT_DISCONNECT)
-		return;
-
-	l2cap_close(chan, 0);
-}
-
-/*
- * Process Received Info Request. We must respond but alas dont
- * support anything as yet so thats easy.
- */
-static void
-l2cap_recv_info_req(struct mbuf *m, struct hci_link *link)
-{
-	l2cap_cmd_hdr_t cmd;
-	l2cap_info_req_cp cp;
-	l2cap_info_rsp_cp rp;
-
-	m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd);
-	m_adj(m, sizeof(cmd));
-
-	m_copydata(m, 0, sizeof(cp), (caddr_t)&cp);
-	m_adj(m, sizeof(cp));
-
-	switch(letoh16(cp.type)) {
-	case L2CAP_CONNLESS_MTU:
-	case L2CAP_EXTENDED_FEATURES:
-	default:
-		rp.type = cp.type;
-		rp.result = htole16(L2CAP_NOT_SUPPORTED);
-
-		l2cap_send_signal(link, L2CAP_INFO_RSP, cmd.ident,
-					sizeof(rp), &rp);
-		break;
-	}
-}
-
-/*
- * Construct signal and wrap in C-Frame for link.
- */
-static int
-l2cap_send_signal(struct hci_link *link, uint8_t code, uint8_t ident,
-			uint16_t length, void *data)
-{
-	struct mbuf *m;
-	l2cap_hdr_t *hdr;
-	l2cap_cmd_hdr_t *cmd;
-
-#ifdef DIAGNOSTIC
-	if (link == NULL)
-		return ENETDOWN;
-
-	if (sizeof(l2cap_cmd_hdr_t) + length > link->hl_mtu)
-		kprintf("(%s) exceeding L2CAP Signal MTU for link!\n",
-		    device_get_nameunit(link->hl_unit->hci_dev));
-#endif
-
-	m = m_gethdr(M_NOWAIT, MT_DATA);
-	if (m == NULL)
-		return ENOMEM;
-
-	hdr = mtod(m, l2cap_hdr_t *);
-	cmd = (l2cap_cmd_hdr_t *)(hdr + 1);
-
-	m->m_len = m->m_pkthdr.len = MHLEN;
-
-	/* Command Data */
-	if (length > 0)
-		m_copyback(m, sizeof(*hdr) + sizeof(*cmd), length, data);
-
-	/* Command Header */
-	cmd->code = code;
-	cmd->ident = ident;
-	cmd->length = htole16(length);
-	length += sizeof(*cmd);
-
-	/* C-Frame Header */
-	hdr->length = htole16(length);
-	hdr->dcid = htole16(L2CAP_SIGNAL_CID);
-	length += sizeof(*hdr);
-
-	if (m->m_pkthdr.len != MAX(MHLEN, length)) {
-		m_freem(m);
-		return ENOMEM;
-	}
-
-	m->m_pkthdr.len = length;
-	m->m_len = MIN(length, MHLEN);
-
-	DPRINTFN(2, "(%s) code %d, ident %d, len %d\n",
-		device_get_nameunit(link->hl_unit->hci_dev), code, ident,
-		length);
-
-	return hci_acl_send(m, link, NULL);
-}
-
-/*
- * Send Command Reject packet.
- */
-static int
-l2cap_send_command_rej(struct hci_link *link, uint8_t ident,
-			uint16_t reason, ...)
-{
-	l2cap_cmd_rej_cp cp;
-	int len = 0;
-	__va_list ap;
-
-	__va_start(ap, reason);
-
-	cp.reason = htole16(reason);
-
-	switch (reason) {
-	case L2CAP_REJ_NOT_UNDERSTOOD:
-		len = 2;
-		break;
-
-	case L2CAP_REJ_MTU_EXCEEDED:
-		len = 4;
-		cp.data[0] = __va_arg(ap, int);		/* SigMTU */
-		cp.data[0] = htole16(cp.data[0]);
-		break;
-
-	case L2CAP_REJ_INVALID_CID:
-		len = 6;
-		cp.data[0] = __va_arg(ap, int);		/* dcid */
-		cp.data[0] = htole16(cp.data[0]);
-		cp.data[1] = __va_arg(ap, int);		/* scid */
-		cp.data[1] = htole16(cp.data[1]);
-		break;
-
-	default:
-		UNKNOWN(reason);
-		return EINVAL;
-	}
-
-	__va_end(ap);
-
-	return l2cap_send_signal(link, L2CAP_COMMAND_REJ, ident, len, &cp);
-}
-
-/*
- * Send Connect Request
- */
-int
-l2cap_send_connect_req(struct l2cap_channel *chan)
-{
-	l2cap_con_req_cp cp;
-	int err;
-
-	err = l2cap_request_alloc(chan, L2CAP_CONNECT_REQ);
-	if (err)
-		return err;
-
-	cp.psm = htole16(chan->lc_raddr.bt_psm);
-	cp.scid = htole16(chan->lc_lcid);
-
-	return l2cap_send_signal(chan->lc_link, L2CAP_CONNECT_REQ,
-				chan->lc_link->hl_lastid, sizeof(cp), &cp);
-}
-
-/*
- * Send Config Request
- *
- * For outgoing config request, we only put options in the packet if they
- * differ from the default and would have to be actioned. We dont support
- * enough option types to make overflowing SigMTU an issue so it can all
- * go in one packet.
- */
-int
-l2cap_send_config_req(struct l2cap_channel *chan)
-{
-	l2cap_cfg_req_cp *cp;
-	l2cap_cfg_opt_t *opt;
-	l2cap_cfg_opt_val_t *val;
-	uint8_t *next, buf[L2CAP_MTU_MINIMUM];
-	int err;
-
-	err = l2cap_request_alloc(chan, L2CAP_CONFIG_REQ);
-	if (err)
-		return err;
-
-	/* Config Header (4 octets) */
-	cp = (l2cap_cfg_req_cp *)buf;
-	cp->dcid = htole16(chan->lc_rcid);
-	cp->flags = 0;	/* "No Continuation" */
-
-	next = buf + sizeof(l2cap_cfg_req_cp);
-
-	/* Incoming MTU (4 octets) */
-	if (chan->lc_imtu != L2CAP_MTU_DEFAULT) {
-		opt = (l2cap_cfg_opt_t *)next;
-		opt->type = L2CAP_OPT_MTU;
-		opt->length = L2CAP_OPT_MTU_SIZE;
-
-		val = (l2cap_cfg_opt_val_t *)(opt + 1);
-		val->mtu = htole16(chan->lc_imtu);
-
-		next += sizeof(l2cap_cfg_opt_t) + L2CAP_OPT_MTU_SIZE;
-	}
-
-	/* Flush Timeout (4 octets) */
-	if (chan->lc_flush != L2CAP_FLUSH_TIMO_DEFAULT) {
-		opt = (l2cap_cfg_opt_t *)next;
-		opt->type = L2CAP_OPT_FLUSH_TIMO;
-		opt->length = L2CAP_OPT_FLUSH_TIMO_SIZE;
-
-		val = (l2cap_cfg_opt_val_t *)(opt + 1);
-		val->flush_timo = htole16(chan->lc_flush);
-
-		next += sizeof(l2cap_cfg_opt_t) + L2CAP_OPT_FLUSH_TIMO_SIZE;
-	}
-
-	/* Outgoing QoS Flow (24 octets) */
-	/* Retransmission & Flow Control (11 octets) */
-	/*
-	 * From here we need to start paying attention to SigMTU as we have
-	 * possibly overflowed the minimum supported..
-	 */
-
-	return l2cap_send_signal(chan->lc_link, L2CAP_CONFIG_REQ,
-				    chan->lc_link->hl_lastid, (int)(next - buf), buf);
-}
-
-/*
- * Send Disconnect Request
- */
-int
-l2cap_send_disconnect_req(struct l2cap_channel *chan)
-{
-	l2cap_discon_req_cp cp;
-	int err;
-
-	err = l2cap_request_alloc(chan, L2CAP_DISCONNECT_REQ);
-	if (err)
-		return err;
-
-	cp.dcid = htole16(chan->lc_rcid);
-	cp.scid = htole16(chan->lc_lcid);
-
-	return l2cap_send_signal(chan->lc_link, L2CAP_DISCONNECT_REQ,
-				    chan->lc_link->hl_lastid, sizeof(cp), &cp);
-}
-
-/*
- * Send Connect Response
- */
-int
-l2cap_send_connect_rsp(struct hci_link *link, uint8_t ident, uint16_t dcid,
-    uint16_t scid, uint16_t result)
-{
-	l2cap_con_rsp_cp cp;
-
-	memset(&cp, 0, sizeof(cp));
-	cp.dcid = htole16(dcid);
-	cp.scid = htole16(scid);
-	cp.result = htole16(result);
-
-	return l2cap_send_signal(link, L2CAP_CONNECT_RSP, ident, sizeof(cp), &cp);
-}
diff --git a/sys/netbt/l2cap_socket.c b/sys/netbt/l2cap_socket.c
deleted file mode 100644
index a458ce0c66..0000000000
--- a/sys/netbt/l2cap_socket.c
+++ /dev/null
@@ -1,515 +0,0 @@
-/* $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */
-/* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
-
-/* load symbolic names */
-#ifdef BLUETOOTH_DEBUG
-#define PRUREQUESTS
-#define PRCOREQUESTS
-#endif
-
-#include <sys/param.h>
-#include <sys/domain.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>	/* for M_NOWAIT */
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/protosw.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/systm.h>
-
-#include <sys/msgport2.h>
-
-#include <vm/vm_zone.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>		/* XXX for EPASSTHROUGH */
-#include <netbt/l2cap.h>
-
-/*
- * L2CAP Sockets
- *
- *	SOCK_SEQPACKET - normal L2CAP connection
- *
- *	SOCK_DGRAM - connectionless L2CAP - XXX not yet
- */
-
-static void l2cap_connecting(void *);
-static void l2cap_connected(void *);
-static void l2cap_disconnected(void *, int);
-static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
-static void l2cap_complete(void *, int);
-static void l2cap_linkmode(void *, int);
-static void l2cap_input(void *, struct mbuf *);
-
-static const struct btproto l2cap_proto = {
-	l2cap_connecting,
-	l2cap_connected,
-	l2cap_disconnected,
-	l2cap_newconn,
-	l2cap_complete,
-	l2cap_linkmode,
-	l2cap_input,
-};
-
-/* sysctl variables */
-int l2cap_sendspace = 4096;
-int l2cap_recvspace = 4096;
-
-/*
- * l2cap_ctloutput(request, socket, level, optname, opt)
- *
- *	Apply configuration commands to channel. This corresponds to
- *	"Reconfigure Channel Request" in the L2CAP specification.
- */
-void
-l2cap_ctloutput(netmsg_t msg)
-{
-	struct socket *so = msg->ctloutput.base.nm_so;
-	struct sockopt *sopt = msg->ctloutput.nm_sopt;
-	struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb;
-	struct mbuf *m;
-	int error = 0;
-
-#ifdef notyet			/* XXX */
-	DPRINTFN(2, "%s\n", prcorequests[req]);
-#endif
-
-	if (pcb == NULL) {
-		error = EINVAL;
-		goto out;
-	}
-
-	if (sopt->sopt_level != BTPROTO_L2CAP) {
-		error = ENOPROTOOPT;
-		goto out;
-	}
-
-	switch(sopt->sopt_dir) {
-	case PRCO_GETOPT:
-		m = m_get(M_NOWAIT, MT_DATA);
-		if (m == NULL) {
-		    error = ENOMEM;
-		    break;
-		}
-		m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *));
-		if (m->m_len == 0) {
-			m_freem(m);
-			m = NULL;
-			error = ENOPROTOOPT;
-		}
-		soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
-		break;
-
-	case PRCO_SETOPT:
-		error = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt);
-		break;
-
-	default:
-		error = ENOPROTOOPT;
-		break;
-	}
-out:
-	lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
-}
-
-/**********************************************************************
- *
- *	L2CAP Protocol socket callbacks
- *
- */
-
-static void
-l2cap_connecting(void *arg)
-{
-	struct socket *so = arg;
-
-	DPRINTF("Connecting\n");
-	soisconnecting(so);
-}
-
-static void
-l2cap_connected(void *arg)
-{
-	struct socket *so = arg;
-
-	DPRINTF("Connected\n");
-	soisconnected(so);
-}
-
-static void
-l2cap_disconnected(void *arg, int err)
-{
-	struct socket *so = arg;
-
-	DPRINTF("Disconnected (%d)\n", err);
-
-	so->so_error = err;
-	soisdisconnected(so);
-}
-
-static void *
-l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
-    struct sockaddr_bt *raddr)
-{
-	struct socket *so = arg;
-
-	DPRINTF("New Connection\n");
-	so = sonewconn(so, 0);
-	if (so == NULL)
-		return NULL;
-
-	soisconnecting(so);
-
-	return so->so_pcb;
-}
-
-static void
-l2cap_complete(void *arg, int count)
-{
-	struct socket *so = arg;
-
-	while (count-- > 0)
-		sbdroprecord(&so->so_snd.sb);
-
-	sowwakeup(so);
-}
-
-static void
-l2cap_linkmode(void *arg, int new)
-{
-	struct socket *so = arg;
-	int mode;
-
-	DPRINTF("auth %s, encrypt %s, secure %s\n",
-		(new & L2CAP_LM_AUTH ? "on" : "off"),
-		(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
-		(new & L2CAP_LM_SECURE ? "on" : "off"));
-
-	(void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
-	if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
-	    || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
-	    || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
-		l2cap_disconnect(so->so_pcb, 0);
-}
-
-static void
-l2cap_input(void *arg, struct mbuf *m)
-{
-	struct socket *so = arg;
-
-	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
-		kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n",
-			__func__, m->m_pkthdr.len);
-		m_freem(m);
-		return;
-	}
-
-	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
-
-	sbappendrecord(&so->so_rcv.sb, m);
-	sorwakeup(so);
-}
-
-
-/*
- * Implementation of usrreqs.
- */
-static void
-l2cap_sdetach(netmsg_t msg)
-{
-	struct socket *so = msg->detach.base.nm_so;
-	int error;
-
-	error = l2cap_detach((struct l2cap_channel **)&so->so_pcb);
-	lwkt_replymsg(&msg->detach.base.lmsg, error);
-}
-
-/*
- * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
- *	 will sofree() it when we return.
- */
-static void
-l2cap_sabort(netmsg_t msg)
-{
-	struct socket *so = msg->abort.base.nm_so;
-	struct l2cap_channel *pcb = so->so_pcb;
-	
-	l2cap_disconnect(pcb, 0);
-	soisdisconnected(so);
-	
-	l2cap_sdetach(msg);
-	/* msg invalid now */
-}
-
-static void
-l2cap_sdisconnect(netmsg_t msg)
-{
-	struct socket *so = msg->disconnect.base.nm_so;
-	struct l2cap_channel *pcb = so->so_pcb;
-	int error;
-	
-	soisdisconnecting(so);
-	
-	error = l2cap_disconnect(pcb, so->so_linger);
-	lwkt_replymsg(&msg->disconnect.base.lmsg, error);
-}
-
-static void
-l2cap_scontrol(netmsg_t msg)
-{
-	lwkt_replymsg(&msg->control.base.lmsg, EPASSTHROUGH);
-}
-
-static void
-l2cap_sattach(netmsg_t msg)
-{
-	struct socket *so = msg->attach.base.nm_so;
-	struct l2cap_channel *pcb = so->so_pcb;
-	int error;
-
-	if (pcb != NULL) {
-		error = EINVAL;
-		goto out;
-	}
-
-	/*
-	 * For L2CAP socket PCB we just use an l2cap_channel structure
-	 * since we have nothing to add..
-	 */
-	error = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL);
-	if (error == 0) {
-		error = l2cap_attach((struct l2cap_channel **)&so->so_pcb,
-				     &l2cap_proto, so);
-	}
-out:
-	lwkt_replymsg(&msg->attach.base.lmsg, error);
-}
-
-static void
-l2cap_sbind (netmsg_t msg)
-{
-	struct socket *so = msg->bind.base.nm_so;
-	struct sockaddr *nam = msg->bind.nm_nam;
-	struct l2cap_channel *pcb = so->so_pcb;
-	struct sockaddr_bt *sa;
-	int error;
-
-	KKASSERT(nam != NULL);
-	sa = (struct sockaddr_bt *)nam;
-
-	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
-		error = EINVAL;
-	} else if (sa->bt_family != AF_BLUETOOTH) {
-		error = EAFNOSUPPORT;
-	} else {
-		error = l2cap_bind(pcb, sa);
-	}
-	lwkt_replymsg(&msg->bind.base.lmsg, error);
-}
-
-static void
-l2cap_sconnect(netmsg_t msg)
-{
-	struct socket *so = msg->connect.base.nm_so;
-	struct sockaddr *nam = msg->connect.nm_nam;
-	struct l2cap_channel *pcb = so->so_pcb;
-	struct sockaddr_bt *sa;
-	int error;
-
-	KKASSERT(nam != NULL);
-	sa = (struct sockaddr_bt *)nam;
-
-	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
-		error = EINVAL;
-	} else if (sa->bt_family != AF_BLUETOOTH) {
-		error = EAFNOSUPPORT;
-	} else {
-		soisconnecting(so);
-		error = l2cap_connect(pcb, sa);
-	}
-	lwkt_replymsg(&msg->connect.base.lmsg, error);
-}
-
-static void
-l2cap_speeraddr(netmsg_t msg)
-{
-	struct socket *so = msg->peeraddr.base.nm_so;
-	struct sockaddr **nam = msg->peeraddr.nm_nam;
-	struct l2cap_channel *pcb = so->so_pcb;
-	struct sockaddr_bt *sa, ssa;
-	int error;
-
-	sa = &ssa;
-	bzero(sa, sizeof *sa);
-	sa->bt_len = sizeof(struct sockaddr_bt);
-	sa->bt_family = AF_BLUETOOTH;
-	error = l2cap_peeraddr(pcb, sa);
-	*nam = dup_sockaddr((struct sockaddr *)sa);
-
-	lwkt_replymsg(&msg->peeraddr.base.lmsg, error);
-}
-
-static void
-l2cap_ssockaddr(netmsg_t msg)
-{
-	struct socket *so = msg->sockaddr.base.nm_so;
-	struct sockaddr **nam = msg->sockaddr.nm_nam;
-	struct l2cap_channel *pcb = so->so_pcb;
-	struct sockaddr_bt *sa, ssa;
-	int error;
-
-	sa = &ssa;
-	bzero(sa, sizeof *sa);
-	sa->bt_len = sizeof(struct sockaddr_bt);
-	sa->bt_family = AF_BLUETOOTH;
-	error = l2cap_sockaddr(pcb, sa);
-	*nam = dup_sockaddr((struct sockaddr *)sa);
-
-	lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
-}
-
-static void
-l2cap_sshutdown(netmsg_t msg)
-{
-	struct socket *so = msg->shutdown.base.nm_so;
-
-	socantsendmore(so);
-
-	lwkt_replymsg(&msg->shutdown.base.lmsg, 0);
-}
-
-static void
-l2cap_ssend(netmsg_t msg)
-{
-	struct socket *so = msg->send.base.nm_so;
-	struct mbuf *m = msg->send.nm_m;
-	struct mbuf *control = msg->send.nm_control;
-	struct l2cap_channel *pcb = so->so_pcb;
-	struct mbuf *m0;
-	int error;
-
-	KKASSERT(m != NULL);
-	if (m->m_pkthdr.len == 0) {
-		error = 0;
-		goto out;
-	}
-
-	if (m->m_pkthdr.len > pcb->lc_omtu) {
-		error = EMSGSIZE;
-		goto out;
-	}
-
-	m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
-	if (m0 == NULL) {
-		error = ENOMEM;
-		goto out;
-	}
-
-	m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
-	if (m0 == NULL) {
-		error = ENOMEM;
-		goto out;
-	}
-
-	/* no use for that */
-	if (control) {
-		m_freem(control);
-		control = NULL;
-	}
-	sbappendrecord(&so->so_snd.sb, m);
-	error = l2cap_send(pcb, m0);
-	m = NULL;
-out:
-	if (m)
-		m_freem(m);
-	if (control)
-		m_freem(control);
-
-	lwkt_replymsg(&msg->send.base.lmsg, error);
-}
-
-static void
-l2cap_saccept(netmsg_t msg)
-{
-	struct socket *so = msg->accept.base.nm_so;
-	struct sockaddr **nam = msg->accept.nm_nam;
-	struct l2cap_channel *pcb = so->so_pcb;
-	struct sockaddr_bt sa;
-	int error;
-		
-	KKASSERT(nam != NULL);
-	
-	bzero(&sa, sizeof (sa) );
-	sa.bt_len = sizeof(struct sockaddr_bt);
-	sa.bt_family = AF_BLUETOOTH;
-
-	error = l2cap_peeraddr(pcb, &sa);
-	*nam = dup_sockaddr((struct sockaddr *)&sa);
-
-	lwkt_replymsg(&msg->accept.base.lmsg, error);
-}
-
-static void
-l2cap_slisten(netmsg_t msg)
-{
-	struct socket *so = msg->listen.base.nm_so;
-	struct l2cap_channel *pcb = so->so_pcb;
-	int error;
-
-	error = l2cap_listen(pcb);
-	lwkt_replymsg(&msg->accept.base.lmsg, error);
-}
-
-
-struct pr_usrreqs l2cap_usrreqs = {
-        .pru_abort = l2cap_sabort,
-        .pru_accept = l2cap_saccept,
-        .pru_attach = l2cap_sattach,
-        .pru_bind = l2cap_sbind,
-        .pru_connect = l2cap_sconnect,
-        .pru_connect2 = pr_generic_notsupp,
-        .pru_control = l2cap_scontrol,
-        .pru_detach = l2cap_sdetach,
-        .pru_disconnect = l2cap_sdisconnect,
-        .pru_listen = l2cap_slisten,
-        .pru_peeraddr = l2cap_speeraddr,
-        .pru_rcvd = pr_generic_notsupp,
-        .pru_rcvoob = pr_generic_notsupp,
-        .pru_send = l2cap_ssend,
-        .pru_sense = pru_sense_null,
-        .pru_shutdown = l2cap_sshutdown,
-        .pru_sockaddr = l2cap_ssockaddr,
-        .pru_sosend = sosend,
-        .pru_soreceive = soreceive
-};
diff --git a/sys/netbt/l2cap_upper.c b/sys/netbt/l2cap_upper.c
deleted file mode 100644
index 2b27b726ba..0000000000
--- a/sys/netbt/l2cap_upper.c
+++ /dev/null
@@ -1,555 +0,0 @@
-/* $OpenBSD: l2cap_upper.c,v 1.2 2007/10/01 16:39:30 krw Exp $ */
-/* $NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $ */
-
-/*-
- * Copyright (c) 2005 Iain Hibbert.
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/systm.h>
-#include <sys/endian.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-
-/*******************************************************************************
- *
- *	L2CAP Channel - Upper Protocol API
- */
-
-/*
- * l2cap_attach(handle, btproto, upper)
- *
- *	attach new l2cap_channel to handle, populate
- *	with reasonable defaults
- */
-int
-l2cap_attach(struct l2cap_channel **handle,
-		const struct btproto *proto, void *upper)
-{
-	struct l2cap_channel *chan;
-
-	KKASSERT(handle != NULL);
-	KKASSERT(proto != NULL);
-	KKASSERT(upper != NULL);
-
-	chan = kmalloc(sizeof(*chan), M_BLUETOOTH, M_NOWAIT | M_ZERO);
-	if (chan == NULL)
-		return ENOMEM;
-
-	chan->lc_proto = proto;
-	chan->lc_upper = upper;
-
-	chan->lc_state = L2CAP_CLOSED;
-
-	chan->lc_lcid = L2CAP_NULL_CID;
-	chan->lc_rcid = L2CAP_NULL_CID;
-
-	chan->lc_laddr.bt_len = sizeof(struct sockaddr_bt);
-	chan->lc_laddr.bt_family = AF_BLUETOOTH;
-	chan->lc_laddr.bt_psm = L2CAP_PSM_ANY;
-
-	chan->lc_raddr.bt_len = sizeof(struct sockaddr_bt);
-	chan->lc_raddr.bt_family = AF_BLUETOOTH;
-	chan->lc_raddr.bt_psm = L2CAP_PSM_ANY;
-
-	chan->lc_imtu = L2CAP_MTU_DEFAULT;
-	chan->lc_omtu = L2CAP_MTU_DEFAULT;
-	chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT;
-
-	memcpy(&chan->lc_iqos, &l2cap_default_qos, sizeof(l2cap_qos_t));
-	memcpy(&chan->lc_oqos, &l2cap_default_qos, sizeof(l2cap_qos_t));
-
-	*handle = chan;
-	return 0;
-}
-
-/*
- * l2cap_bind(l2cap_channel, sockaddr)
- *
- *	set local address of channel
- */
-int
-l2cap_bind(struct l2cap_channel *chan, struct sockaddr_bt *addr)
-{
-
-	memcpy(&chan->lc_laddr, addr, sizeof(struct sockaddr_bt));
-	return 0;
-}
-
-/*
- * l2cap_sockaddr(l2cap_channel, sockaddr)
- *
- *	get local address of channel
- */
-int
-l2cap_sockaddr(struct l2cap_channel *chan, struct sockaddr_bt *addr)
-{
-	memcpy(addr, &chan->lc_laddr, sizeof(struct sockaddr_bt));
-	return 0;
-}
-
-/*
- * l2cap_connect(l2cap_channel, sockaddr)
- *
- *	Initiate a connection to destination. This corresponds to
- *	"Open Channel Request" in the L2CAP specification and will
- *	result in one of the following:
- *
- *		proto->connected(upper)
- *		proto->disconnected(upper, error)
- *
- *	and, optionally
- *		proto->connecting(upper)
- */
-int
-l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest)
-{
-	struct hci_unit *unit;
-	int err;
-
-	memcpy(&chan->lc_raddr, dest, sizeof(struct sockaddr_bt));
-
-	if (L2CAP_PSM_INVALID(chan->lc_raddr.bt_psm))
-		return EINVAL;
-
-	if (bdaddr_any(&chan->lc_raddr.bt_bdaddr))
-		return EDESTADDRREQ;
-
-	/* set local address if it needs setting */
-	if (bdaddr_any(&chan->lc_laddr.bt_bdaddr)) {
-		err = hci_route_lookup(&chan->lc_laddr.bt_bdaddr,
-					&chan->lc_raddr.bt_bdaddr);
-		if (err)
-			return err;
-	}
-
-	unit = hci_unit_lookup(&chan->lc_laddr.bt_bdaddr);
-	if (unit == NULL)
-		return EHOSTUNREACH;
-
-	/* attach to active list */
-	err = l2cap_cid_alloc(chan);
-	if (err)
-		return err;
-
-	/* open link to remote device */
-	chan->lc_link = hci_acl_open(unit, &chan->lc_raddr.bt_bdaddr);
-	if (chan->lc_link == NULL)
-		return EHOSTUNREACH;
-
-	/* set the link mode */
-	err = l2cap_setmode(chan);
-	if (err == EINPROGRESS) {
-		chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ;
-		(*chan->lc_proto->connecting)(chan->lc_upper);
-		return 0;
-	}
-	if (err)
-		goto fail;
-
-	/*
-	 * We can queue a connect request now even though the link may
-	 * not yet be open; Our mode setting is assured, and the queue
-	 * will be started automatically at the right time.
-	 */
-	chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP;
-	err = l2cap_send_connect_req(chan);
-	if (err)
-		goto fail;
-
-	return 0;
-
-fail:
-	chan->lc_state = L2CAP_CLOSED;
-	hci_acl_close(chan->lc_link, err);
-	chan->lc_link = NULL;
-	return err;
-}
-
-/*
- * l2cap_peeraddr(l2cap_channel, sockaddr)
- *
- *	get remote address of channel
- */
-int
-l2cap_peeraddr(struct l2cap_channel *chan, struct sockaddr_bt *addr)
-{
-	memcpy(addr, &chan->lc_raddr, sizeof(struct sockaddr_bt));
-	return 0;
-}
-
-/*
- * l2cap_disconnect(l2cap_channel, linger)
- *
- *	Initiate L2CAP disconnection. This corresponds to
- *	"Close Channel Request" in the L2CAP specification
- *	and will result in a call to
- *
- *		proto->disconnected(upper, error)
- *
- *	when the disconnection is complete. If linger is set,
- *	the call will not be made until data has flushed from
- *	the queue.
- */
-int
-l2cap_disconnect(struct l2cap_channel *chan, int linger)
-{
-	int err = 0;
-
-	if (chan->lc_state == L2CAP_CLOSED
-	    || chan->lc_state == L2CAP_WAIT_DISCONNECT)
-		return EINVAL;
-
-	chan->lc_flags |= L2CAP_SHUTDOWN;
-
-	/*
-	 * no need to do anything unless the queue is empty or
-	 * we are not lingering..
-	 */
-	if ((IF_QEMPTY(&chan->lc_txq) && chan->lc_pending == 0)
-	    || linger == 0) {
-		chan->lc_state = L2CAP_WAIT_DISCONNECT;
-		err = l2cap_send_disconnect_req(chan);
-		if (err)
-			l2cap_close(chan, err);
-	}
-	return err;
-}
-
-/*
- * l2cap_detach(handle)
- *
- *	Detach l2cap channel from handle & close it down
- */
-int
-l2cap_detach(struct l2cap_channel **handle)
-{
-	struct l2cap_channel *chan;
-
-	chan = *handle;
-	*handle = NULL;
-
-	if (chan->lc_state != L2CAP_CLOSED)
-		l2cap_close(chan, 0);
-
-	if (chan->lc_lcid != L2CAP_NULL_CID) {
-		LIST_REMOVE(chan, lc_ncid);
-		chan->lc_lcid = L2CAP_NULL_CID;
-	}
-
-	IF_DRAIN(&chan->lc_txq);
-
-	/*
-	 * Could implement some kind of delayed expunge to make sure that the
-	 * CID is really dead before it becomes available for reuse?
-	 */
-
-	kfree(chan, M_BLUETOOTH);
-	return 0;
-}
-
-/*
- * l2cap_listen(l2cap_channel)
- *
- *	Use this channel as a listening post (until detached). This will
- *	result in calls to:
- *
- *		proto->newconn(upper, laddr, raddr)
- *
- *	for incoming connections matching the psm and local address of the
- *	channel (NULL psm/address are permitted and match any protocol/device).
- *
- *	The upper layer should create and return a new channel.
- *
- *	You cannot use this channel for anything else subsequent to this call
- */
-int
-l2cap_listen(struct l2cap_channel *chan)
-{
-	struct l2cap_channel *used, *prev = NULL;
-
-	if (chan->lc_lcid != L2CAP_NULL_CID)
-		return EINVAL;
-
-	if (chan->lc_laddr.bt_psm != L2CAP_PSM_ANY
-	    && L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm))
-		return EADDRNOTAVAIL;
-
-	/*
-	 * This CID is irrelevant, as the channel is not stored on the active
-	 * list and the socket code does not allow operations on listening
-	 * sockets, but we set it so the detach code knows to LIST_REMOVE the
-	 * channel.
-	 */
-	chan->lc_lcid = L2CAP_SIGNAL_CID;
-
-	/*
-	 * The list of listening channels is stored in an order such that new
-	 * listeners dont usurp current listeners, but that specific listening
-	 * takes precedence over promiscuous, and the connect request code can
-	 * easily use the first matching entry.
-	 */
-	LIST_FOREACH(used, &l2cap_listen_list, lc_ncid) {
-		if (used->lc_laddr.bt_psm < chan->lc_laddr.bt_psm)
-			break;
-
-		if (used->lc_laddr.bt_psm == chan->lc_laddr.bt_psm
-			&& bdaddr_any(&used->lc_laddr.bt_bdaddr)
-			&& !bdaddr_any(&chan->lc_laddr.bt_bdaddr))
-			break;
-
-		prev = used;
-	}
-
-	if (prev == NULL)
-		LIST_INSERT_HEAD(&l2cap_listen_list, chan, lc_ncid);
-	else
-		LIST_INSERT_AFTER(prev, chan, lc_ncid);
-
-	return 0;
-}
-
-/*
- * l2cap_send(l2cap_channel, mbuf)
- *
- *	Output SDU on channel described by channel. This corresponds
- *	to "Send Data Request" in the L2CAP specification. The upper
- *	layer will be notified when SDU's have completed sending by a
- *	call to:
- *
- *		proto->complete(upper, n)
- *
- *	(currently n == 1)
- *
- *	Note: I'm not sure how this will work out, but I think that
- *	if outgoing Retransmission Mode or Flow Control Mode is
- *	negotiated then this call will not be made until the SDU has
- *	been acknowleged by the peer L2CAP entity. For 'Best Effort'
- *	it will be made when the packet has cleared the controller
- *	buffers.
- *
- *	We only support Basic mode so far, so encapsulate with a
- *	B-Frame header and start sending if we are not already
- */
-int
-l2cap_send(struct l2cap_channel *chan, struct mbuf *m)
-{
-	l2cap_hdr_t *hdr;
-	int plen;
-
-	if (chan->lc_state == L2CAP_CLOSED) {
-		m_freem(m);
-		return ENOTCONN;
-	}
-
-	plen = m->m_pkthdr.len;
-
-	DPRINTFN(5, "send %d bytes on CID #%d (pending = %d)\n",
-		plen, chan->lc_lcid, chan->lc_pending);
-
-	/* Encapsulate with B-Frame */
-	M_PREPEND(m, sizeof(l2cap_hdr_t), M_NOWAIT);
-	if (m == NULL)
-		return ENOMEM;
-
-	hdr = mtod(m, l2cap_hdr_t *);
-	hdr->length = htole16(plen);
-	hdr->dcid = htole16(chan->lc_rcid);
-
-	/* Queue it on our list */
-	IF_ENQUEUE(&chan->lc_txq, m);
-
-	/* If we are not sending, then start doing so */
-	if (chan->lc_pending == 0)
-		return l2cap_start(chan);
-
-	return 0;
-}
-
-/*
- * l2cap_setopt(l2cap_channel, opt, addr)
- *
- *	Apply configuration options to channel. This corresponds to
- *	"Configure Channel Request" in the L2CAP specification.
- *
- *	for SO_L2CAP_LM, the settings will take effect when the
- *	channel is established. If the channel is already open,
- *	a call to
- *		proto->linkmode(upper, new)
- *
- *	will be made when the change is complete.
- */
-int
-l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr)
-{
-	int mode, err = 0;
-	uint16_t mtu;
-
-	switch (opt) {
-	case SO_L2CAP_IMTU:	/* set Incoming MTU */
-		mtu = *(uint16_t *)addr;
-		if (mtu < L2CAP_MTU_MINIMUM)
-			err = EINVAL;
-		else if (chan->lc_state == L2CAP_CLOSED)
-			chan->lc_imtu = mtu;
-		else
-			err = EBUSY;
-
-		break;
-
-	case SO_L2CAP_LM:	/* set link mode */
-		mode = *(int *)addr;
-		mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH);
-
-		if (mode & L2CAP_LM_SECURE)
-			mode |= L2CAP_LM_ENCRYPT;
-
-		if (mode & L2CAP_LM_ENCRYPT)
-			mode |= L2CAP_LM_AUTH;
-
-		chan->lc_mode = mode;
-
-		if (chan->lc_state == L2CAP_OPEN)
-			err = l2cap_setmode(chan);
-
-		break;
-
-	case SO_L2CAP_OQOS:	/* set Outgoing QoS flow spec */
-	case SO_L2CAP_FLUSH:	/* set Outgoing Flush Timeout */
-	default:
-		err = ENOPROTOOPT;
-		break;
-	}
-
-	return err;
-}
-
-
-/*
- * Used in l2cap_socket for set options, coming from socket.
- */
-int
-l2cap_setopt2(struct l2cap_channel *chan, int opt, struct socket *so,
-    struct sockopt *sopt)
-{
-	int mode, err = 0;
-	uint16_t mtu;
-
-	switch (opt) {
-	case SO_L2CAP_IMTU:	/* set Incoming MTU */
-		err = soopt_to_kbuf(sopt, &mtu, sizeof(uint16_t),
-		    sizeof(uint16_t)); 
-		if (err)
-			break;
-
-		if (mtu < L2CAP_MTU_MINIMUM)
-			err = EINVAL;
-		else if (chan->lc_state == L2CAP_CLOSED)
-			chan->lc_imtu = mtu;
-		else
-			err = EBUSY;
-
-		break;
-
-	case SO_L2CAP_LM:	/* set link mode */
-		err = soopt_to_kbuf(sopt, &mode, sizeof(int), sizeof(int)); 
-		if (err)
-			break;
-
-		mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH);
-
-		if (mode & L2CAP_LM_SECURE)
-			mode |= L2CAP_LM_ENCRYPT;
-		if (mode & L2CAP_LM_ENCRYPT)
-			mode |= L2CAP_LM_AUTH;
-		chan->lc_mode = mode;
-
-		if (chan->lc_state == L2CAP_OPEN)
-			err = l2cap_setmode(chan);
-
-		break;
-
-	case SO_L2CAP_OQOS:	/* set Outgoing QoS flow spec */
-	case SO_L2CAP_FLUSH:	/* set Outgoing Flush Timeout */
-	default:
-		err = ENOPROTOOPT;
-		break;
-	}
-	return err;
-}
-
-/*
- * l2cap_getopt(l2cap_channel, opt, addr)
- *
- *	Return configuration parameters.
- */
-int
-l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr)
-{
-
-	switch (opt) {
-	case SO_L2CAP_IMTU:	/* get Incoming MTU */
-		*(uint16_t *)addr = chan->lc_imtu;
-		return sizeof(uint16_t);
-
-	case SO_L2CAP_OMTU:	/* get Outgoing MTU */
-		*(uint16_t *)addr = chan->lc_omtu;
-		return sizeof(uint16_t);
-
-	case SO_L2CAP_IQOS:	/* get Incoming QoS flow spec */
-		memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t));
-		return sizeof(l2cap_qos_t);
-
-	case SO_L2CAP_OQOS:	/* get Outgoing QoS flow spec */
-		memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t));
-		return sizeof(l2cap_qos_t);
-
-	case SO_L2CAP_FLUSH:	/* get Flush Timeout */
-		*(uint16_t *)addr = chan->lc_flush;
-		return sizeof(uint16_t);
-
-	case SO_L2CAP_LM:	/* get link mode */
-		*(int *)addr = chan->lc_mode;
-		return sizeof(int);
-
-	default:
-		break;
-	}
-
-	return 0;
-}
diff --git a/sys/netbt/rfcomm.h b/sys/netbt/rfcomm.h
deleted file mode 100644
index ff9c324ad5..0000000000
--- a/sys/netbt/rfcomm.h
+++ /dev/null
@@ -1,432 +0,0 @@
-/* $DragonFly: src/sys/netbt/rfcomm.h,v 1.2 2008/03/18 13:41:42 hasso Exp $ */
-/* $OpenBSD: src/sys/netbt/rfcomm.h,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: rfcomm.h,v 1.6 2007/11/20 20:25:58 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 Maksim Yevmenkin <m_evmenkin@yahoo.com>
- * 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.
- *
- * $Id: rfcomm.h,v 1.6 2007/11/20 20:25:58 plunky Exp $
- * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h,v 1.4 2005/01/11 01:39:53 emax Exp $
- */
-
-#ifndef _NETBT_RFCOMM_H_
-#define _NETBT_RFCOMM_H_
-
-#include <sys/types.h>
-
-/*************************************************************************
- *************************************************************************
- **				RFCOMM					**
- *************************************************************************
- *************************************************************************/
-
-#define RFCOMM_MTU_MAX			32767
-#define RFCOMM_MTU_MIN			23
-#define RFCOMM_MTU_DEFAULT		127
-
-#define RFCOMM_CREDITS_MAX		255	/* in any single packet */
-#define RFCOMM_CREDITS_DEFAULT		7	/* default initial value */
-
-#define RFCOMM_CHANNEL_ANY		0
-#define RFCOMM_CHANNEL_MIN		1
-#define RFCOMM_CHANNEL_MAX		30
-
-/* RFCOMM frame types */
-#define RFCOMM_FRAME_SABM		0x2f
-#define RFCOMM_FRAME_DISC		0x43
-#define RFCOMM_FRAME_UA			0x63
-#define RFCOMM_FRAME_DM			0x0f
-#define RFCOMM_FRAME_UIH		0xef
-
-/* RFCOMM MCC commands */
-#define RFCOMM_MCC_TEST			0x08	/* Test */
-#define RFCOMM_MCC_FCON			0x28	/* Flow Control on */
-#define RFCOMM_MCC_FCOFF		0x18	/* Flow Control off */
-#define RFCOMM_MCC_MSC			0x38	/* Modem Status Command */
-#define RFCOMM_MCC_RPN			0x24	/* Remote Port Negotiation */
-#define RFCOMM_MCC_RLS			0x14	/* Remote Line Status */
-#define RFCOMM_MCC_PN			0x20	/* Port Negotiation */
-#define RFCOMM_MCC_NSC			0x04	/* Non Supported Command */
-
-/* RFCOMM modem signals */
-#define RFCOMM_MSC_FC			0x02	/* Flow Control asserted */
-#define RFCOMM_MSC_RTC			0x04	/* Ready To Communicate */
-#define RFCOMM_MSC_RTR			0x08	/* Ready To Receive */
-#define RFCOMM_MSC_IC			0x40	/* Incomming Call (RING) */
-#define RFCOMM_MSC_DV			0x80	/* Data Valid */
-
-/* RPN parameters - baud rate */
-#define RFCOMM_RPN_BR_2400		0x0
-#define RFCOMM_RPN_BR_4800		0x1
-#define RFCOMM_RPN_BR_7200		0x2
-#define RFCOMM_RPN_BR_9600		0x3
-#define RFCOMM_RPN_BR_19200		0x4
-#define RFCOMM_RPN_BR_38400		0x5
-#define RFCOMM_RPN_BR_57600		0x6
-#define RFCOMM_RPN_BR_115200		0x7
-#define RFCOMM_RPN_BR_230400		0x8
-
-/* RPN parameters - data bits */
-#define RFCOMM_RPN_DATA_5		0x0
-#define RFCOMM_RPN_DATA_6		0x1
-#define RFCOMM_RPN_DATA_7		0x2
-#define RFCOMM_RPN_DATA_8		0x3
-
-/* RPN parameters - stop bit */
-#define RFCOMM_RPN_STOP_1		0
-#define RFCOMM_RPN_STOP_15		1
-
-/* RPN parameters - parity enable */
-#define RFCOMM_RPN_PARITY_NONE		0x0
-
-/* RPN parameters - parity type */
-#define RFCOMM_RPN_PARITY_ODD		0x0
-#define RFCOMM_RPN_PARITY_EVEN		0x1
-#define RFCOMM_RPN_PARITY_MARK		0x2
-#define RFCOMM_RPN_PARITY_SPACE		0x3
-
-/* RPN parameters - default line_setting */
-#define RFCOMM_RPN_8_N_1		0x03
-
-/* RPN parameters - flow control */
-#define RFCOMM_RPN_XON_CHAR		0x11
-#define RFCOMM_RPN_XOFF_CHAR		0x13
-#define RFCOMM_RPN_FLOW_NONE		0x00
-
-/* RPN parameters - mask */
-#define RFCOMM_RPN_PM_RATE		0x0001
-#define RFCOMM_RPN_PM_DATA		0x0002
-#define RFCOMM_RPN_PM_STOP		0x0004
-#define RFCOMM_RPN_PM_PARITY		0x0008
-#define RFCOMM_RPN_PM_PTYPE		0x0010
-#define RFCOMM_RPN_PM_XON		0x0020
-#define RFCOMM_RPN_PM_XOFF		0x0040
-
-#define RFCOMM_RPN_PM_FLOW		0x3f00
-
-#define RFCOMM_RPN_PM_ALL		0x3f7f
-
-/* RFCOMM command frame header */
-struct rfcomm_cmd_hdr
-{
-	uint8_t		address;
-	uint8_t		control;
-	uint8_t		length;
-	uint8_t		fcs;
-} __attribute__ ((__packed__));
-
-/* RFCOMM MSC command */
-struct rfcomm_mcc_msc
-{
-	uint8_t		address;
-	uint8_t		modem;
-	uint8_t		brk;
-} __attribute__ ((__packed__));
-
-/* RFCOMM RPN command */
-struct rfcomm_mcc_rpn
-{
-	uint8_t		dlci;
-	uint8_t		bit_rate;
-	uint8_t		line_settings;
-	uint8_t		flow_control;
-	uint8_t		xon_char;
-	uint8_t		xoff_char;
-	uint16_t	param_mask;
-} __attribute__ ((__packed__));
-
-/* RFCOMM RLS command */
-struct rfcomm_mcc_rls
-{
-	uint8_t		address;
-	uint8_t		status;
-} __attribute__ ((__packed__));
-
-/* RFCOMM PN command */
-struct rfcomm_mcc_pn
-{
-	uint8_t		dlci;
-	uint8_t		flow_control;
-	uint8_t		priority;
-	uint8_t		ack_timer;
-	uint16_t	mtu;
-	uint8_t		max_retrans;
-	uint8_t		credits;
-} __attribute__ ((__packed__));
-
-/* RFCOMM frame parsing macros */
-#define RFCOMM_DLCI(b)			(((b) & 0xfc) >> 2)
-#define RFCOMM_TYPE(b)			(((b) & 0xef))
-
-#define RFCOMM_EA(b)			(((b) & 0x01))
-#define RFCOMM_CR(b)			(((b) & 0x02) >> 1)
-#define RFCOMM_PF(b)			(((b) & 0x10) >> 4)
-
-#define RFCOMM_CHANNEL(dlci)		(((dlci) >> 1) & 0x2f)
-#define RFCOMM_DIRECTION(dlci)		((dlci) & 0x1)
-
-#define RFCOMM_MKADDRESS(cr, dlci) \
-	((((dlci) & 0x3f) << 2) | ((cr) << 1) | 0x01)
-
-#define RFCOMM_MKCONTROL(type, pf)	((((type) & 0xef) | ((pf) << 4)))
-#define RFCOMM_MKDLCI(dir, channel)	((((channel) & 0x1f) << 1) | (dir))
-
-/* RFCOMM MCC macros */
-#define RFCOMM_MCC_TYPE(b)		(((b) & 0xfc) >> 2)
-#define RFCOMM_MCC_LENGTH(b)		(((b) & 0xfe) >> 1)
-#define RFCOMM_MKMCC_TYPE(cr, type)	((((type) << 2) | ((cr) << 1) | 0x01))
-
-/* RPN macros */
-#define RFCOMM_RPN_DATA_BITS(line)	((line) & 0x3)
-#define RFCOMM_RPN_STOP_BITS(line)	(((line) >> 2) & 0x1)
-#define RFCOMM_RPN_PARITY(line)		(((line) >> 3) & 0x1)
-
-/*************************************************************************
- *************************************************************************
- **			SOCK_STREAM RFCOMM sockets			**
- *************************************************************************
- *************************************************************************/
-
-/* Socket options */
-#define SO_RFCOMM_MTU		1	/* mtu */
-#define SO_RFCOMM_FC_INFO	2	/* flow control info (below) */
-#define SO_RFCOMM_LM		3	/* link mode */
-
-/* Flow control information */
-struct rfcomm_fc_info {
-	uint8_t		lmodem;		/* modem signals (local) */
-	uint8_t		rmodem;		/* modem signals (remote) */
-	uint8_t		tx_cred;	/* TX credits */
-	uint8_t		rx_cred;	/* RX credits */
-	uint8_t		cfc;		/* credit flow control */
-	uint8_t		reserved;
-};
-
-/* RFCOMM link mode flags */
-#define RFCOMM_LM_AUTH		(1<<0)	/* want authentication */
-#define RFCOMM_LM_ENCRYPT	(1<<1)	/* want encryption */
-#define RFCOMM_LM_SECURE	(1<<2)	/* want secured link */
-
-#ifdef _KERNEL
-
-/* sysctl variables */
-extern int rfcomm_sendspace;
-extern int rfcomm_recvspace;
-extern int rfcomm_mtu_default;
-extern int rfcomm_ack_timeout;
-extern int rfcomm_mcc_timeout;
-
-/*
- * Bluetooth RFCOMM session data
- * One L2CAP connection == one RFCOMM session
- */
-
-/* Credit note */
-struct rfcomm_credit {
-	struct rfcomm_dlc		*rc_dlc;	/* owner */
-	uint16_t			 rc_len;	/* length */
-	STAILQ_ENTRY(rfcomm_credit)	 rc_next;	/* next credit */
-};
-
-/* RFCOMM session data (one L2CAP channel) */
-struct rfcomm_session {
-	struct l2cap_channel		*rs_l2cap;	/* L2CAP pointer */
-	uint16_t			 rs_flags;	/* session flags */
-	uint16_t			 rs_state;	/* session state */
-	uint16_t			 rs_mtu;	/* default MTU */
-
-	STAILQ_HEAD(,rfcomm_credit)	 rs_credits;	/* credit notes */
-	LIST_HEAD(,rfcomm_dlc)		 rs_dlcs;	/* DLC list */
-
-	struct callout			 rs_timeout;	/* timeout */
-
-	LIST_ENTRY(rfcomm_session)	 rs_next;	/* next session */
-};
-
-LIST_HEAD(rfcomm_session_list, rfcomm_session);
-extern struct rfcomm_session_list rfcomm_session_active;
-extern struct rfcomm_session_list rfcomm_session_listen;
-
-/* Session state */
-#define RFCOMM_SESSION_CLOSED		0
-#define RFCOMM_SESSION_WAIT_CONNECT	1
-#define RFCOMM_SESSION_OPEN		2
-#define RFCOMM_SESSION_WAIT_DISCONNECT	3
-#define RFCOMM_SESSION_LISTEN		4
-
-/* Session flags */
-#define RFCOMM_SESSION_INITIATOR	(1 << 0) /* we are initiator */
-#define RFCOMM_SESSION_CFC		(1 << 1) /* credit flow control */
-#define RFCOMM_SESSION_LFC		(1 << 2) /* local flow control */
-#define RFCOMM_SESSION_RFC		(1 << 3) /* remote flow control */
-#define RFCOMM_SESSION_FREE		(1 << 4) /* self lock out for free */
-
-#define IS_INITIATOR(rs)	((rs)->rs_flags & RFCOMM_SESSION_INITIATOR)
-
-/* Bluetooth RFCOMM DLC data (connection) */
-struct rfcomm_dlc {
-	struct rfcomm_session	*rd_session; /* RFCOMM session */
-	uint8_t			 rd_dlci;    /* RFCOMM DLCI */
-
-	uint16_t		 rd_flags;   /* DLC flags */
-	uint16_t		 rd_state;   /* DLC state */
-	uint16_t		 rd_mtu;     /* MTU */
-	int			 rd_mode;    /* link mode */
-
-	struct sockaddr_bt	 rd_laddr;   /* local address */
-	struct sockaddr_bt	 rd_raddr;   /* remote address */
-
-	uint8_t			 rd_lmodem;  /* local modem signls */
-	uint8_t			 rd_rmodem;  /* remote modem signals */
-
-	int			 rd_rxcred;  /* receive credits (sent) */
-	size_t			 rd_rxsize;  /* receive buffer (bytes, avail) */
-	int			 rd_txcred;  /* transmit credits (unused) */
-	int			 rd_pending; /* packets sent but not complete */
-
-	struct callout		 rd_timeout; /* timeout */
-	struct mbuf		*rd_txbuf;   /* transmit buffer */
-
-	const struct btproto	*rd_proto;   /* upper layer callbacks */
-	void			*rd_upper;   /* upper layer argument */
-
-	LIST_ENTRY(rfcomm_dlc)	 rd_next;    /* next dlc on session */
-};
-
-/*
- * Credit Flow Control works in the following way.
- *
- * txcred is how many packets we can send. Received credit
- * is added to this value, and it is decremented each time
- * we send a packet.
- *
- * rxsize is the number of bytes that are available in the
- * upstream receive buffer.
- *
- * rxcred is the number of credits that we have previously
- * sent that are still unused. This value will be decreased
- * for each packet we receive and we will add to it when we
- * send credits. We calculate the amount of credits to send
- * by the cunning formula "(space / mtu) - sent" so that if
- * we get a bunch of small packets, we can continue sending
- * credits without risking buffer overflow.
- */
-
-/* DLC flags */
-#define RFCOMM_DLC_DETACH		(1 << 0) /* DLC to be detached */
-#define RFCOMM_DLC_SHUTDOWN		(1 << 1) /* DLC to be shutdown */
-
-/* DLC state */
-#define RFCOMM_DLC_CLOSED		0	/* no session */
-#define RFCOMM_DLC_WAIT_SESSION		1	/* waiting for session */
-#define RFCOMM_DLC_WAIT_CONNECT		2	/* waiting for connect */
-#define RFCOMM_DLC_WAIT_SEND_SABM	3	/* waiting to send SABM */
-#define RFCOMM_DLC_WAIT_SEND_UA		4	/* waiting to send UA */
-#define RFCOMM_DLC_WAIT_RECV_UA		5	/* waiting to receive UA */
-#define RFCOMM_DLC_OPEN			6	/* can send/receive */
-#define RFCOMM_DLC_WAIT_DISCONNECT	7	/* waiting for disconnect */
-#define RFCOMM_DLC_LISTEN		8	/* listening DLC */
-
-/*
- * Bluetooth RFCOMM socket kernel prototypes
- */
-
-extern struct pr_usrreqs rfcomm_usrreqs;
-struct socket;
-union netmsg;
-
-/* rfcomm_dlc.c */
-struct rfcomm_dlc *rfcomm_dlc_lookup(struct rfcomm_session *, int);
-struct rfcomm_dlc *rfcomm_dlc_newconn(struct rfcomm_session *, int);
-void rfcomm_dlc_close(struct rfcomm_dlc *, int);
-void rfcomm_dlc_timeout(void *);
-int rfcomm_dlc_setmode(struct rfcomm_dlc *);
-int rfcomm_dlc_connect(struct rfcomm_dlc *);
-int rfcomm_dlc_open(struct rfcomm_dlc *);
-void rfcomm_dlc_start(struct rfcomm_dlc *);
-
-/* rfcomm_session.c */
-void rfcomm_init(void);
-struct rfcomm_session *rfcomm_session_alloc(struct rfcomm_session_list *, struct sockaddr_bt *);
-struct rfcomm_session *rfcomm_session_lookup(struct sockaddr_bt *, struct sockaddr_bt *);
-void rfcomm_session_free(struct rfcomm_session *);
-int rfcomm_session_send_frame(struct rfcomm_session *, int, int);
-int rfcomm_session_send_uih(struct rfcomm_session *, struct rfcomm_dlc *, int, struct mbuf *);
-int rfcomm_session_send_mcc(struct rfcomm_session *, int, uint8_t, void *, int);
-void rfcomm_session_timeout(void *);
-
-/* rfcomm_socket.c */
-int rfcomm_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *);
-void rfcomm_ctloutput(union netmsg *);
-
-/* rfcomm_upper.c */
-int rfcomm_attach(struct rfcomm_dlc **, const struct btproto *, void *);
-int rfcomm_bind(struct rfcomm_dlc *, struct sockaddr_bt *);
-int rfcomm_sockaddr(struct rfcomm_dlc *, struct sockaddr_bt *);
-int rfcomm_connect(struct rfcomm_dlc *, struct sockaddr_bt *);
-int rfcomm_peeraddr(struct rfcomm_dlc *, struct sockaddr_bt *);
-int rfcomm_disconnect(struct rfcomm_dlc *, int);
-int rfcomm_detach(struct rfcomm_dlc **);
-int rfcomm_listen(struct rfcomm_dlc *);
-int rfcomm_send(struct rfcomm_dlc *, struct mbuf *);
-int rfcomm_rcvd(struct rfcomm_dlc *, size_t);
-int rfcomm_setopt(struct rfcomm_dlc *, int, void *);
-int rfcomm_setopt2(struct rfcomm_dlc *, int, struct socket *, struct sockopt *);
-int rfcomm_getopt(struct rfcomm_dlc *, int, void *);
-
-extern vm_zone_t rfcomm_credit_pool;
-#endif /* _KERNEL */
-
-#endif /* _NETBT_RFCOMM_H_ */
diff --git a/sys/netbt/rfcomm_dlc.c b/sys/netbt/rfcomm_dlc.c
deleted file mode 100644
index 88c7706752..0000000000
--- a/sys/netbt/rfcomm_dlc.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/* $OpenBSD: src/sys/netbt/rfcomm_dlc.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: rfcomm_dlc.c,v 1.4 2007/11/03 17:20:17 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/systm.h>
-#include <sys/endian.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-#include <netbt/rfcomm.h>
-
-/*
- * rfcomm_dlc_lookup(rfcomm_session, dlci)
- *
- * Find DLC on session with matching dlci
- */
-struct rfcomm_dlc *
-rfcomm_dlc_lookup(struct rfcomm_session *rs, int dlci)
-{
-	struct rfcomm_dlc *dlc;
-
-	LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
-		if (dlc->rd_dlci == dlci)
-			break;
-	}
-
-	return dlc;
-}
-
-/*
- * rfcomm_dlc_newconn(rfcomm_session, dlci)
- *
- * handle a new dlc request (since its called from a couple of places)
- */
-struct rfcomm_dlc *
-rfcomm_dlc_newconn(struct rfcomm_session *rs, int dlci)
-{
-	struct rfcomm_session *ls;
-	struct rfcomm_dlc *new, *dlc, *any, *best;
-	struct sockaddr_bt laddr, raddr, addr;
-	int chan;
-
-	/*
-	 * Search amongst the listening DLC community for the best match for
-	 * address & channel. We keep listening DLC's hanging on listening
-	 * sessions in a last first order, so scan the entire bunch and keep
-	 * a note of the best address and BDADDR_ANY matches in order to find
-	 * the oldest and most specific match.
-	 */
-	l2cap_sockaddr(rs->rs_l2cap, &laddr);
-	l2cap_peeraddr(rs->rs_l2cap, &raddr);
-	chan = RFCOMM_CHANNEL(dlci);
-	new = NULL;
-
-	any = best = NULL;
-	LIST_FOREACH(ls, &rfcomm_session_listen, rs_next) {
-		l2cap_sockaddr(ls->rs_l2cap, &addr);
-
-		if (addr.bt_psm != laddr.bt_psm)
-			continue;
-
-		if (bdaddr_same(&laddr.bt_bdaddr, &addr.bt_bdaddr)) {
-			LIST_FOREACH(dlc, &ls->rs_dlcs, rd_next) {
-				if (dlc->rd_laddr.bt_channel == chan)
-					best = dlc;
-			}
-		}
-
-		if (bdaddr_any(&addr.bt_bdaddr)) {
-			LIST_FOREACH(dlc, &ls->rs_dlcs, rd_next) {
-				if (dlc->rd_laddr.bt_channel == chan)
-					any = dlc;
-			}
-		}
-	}
-
-	dlc = best ? best : any;
-
-	/* XXX
-	 * Note that if this fails, we could have missed a chance to open
-	 * a connection - really need to rewrite the strategy for storing
-	 * listening DLC's so all can be checked in turn..
-	 */
-	if (dlc != NULL)
-		new = (*dlc->rd_proto->newconn)(dlc->rd_upper, &laddr, &raddr);
-
-	if (new == NULL) {
-		rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
-		return NULL;
-	}
-
-	new->rd_dlci = dlci;
-	new->rd_mtu = rfcomm_mtu_default;
-	new->rd_mode = dlc->rd_mode;
-
-	memcpy(&new->rd_laddr, &laddr, sizeof(struct sockaddr_bt));
-	new->rd_laddr.bt_channel = chan;
-
-	memcpy(&new->rd_raddr, &raddr, sizeof(struct sockaddr_bt));
-	new->rd_raddr.bt_channel = chan;
-
-	new->rd_session = rs;
-	new->rd_state = RFCOMM_DLC_WAIT_CONNECT;
-	LIST_INSERT_HEAD(&rs->rs_dlcs, new, rd_next);
-
-	return new;
-}
-
-/*
- * rfcomm_dlc_close(dlc, error)
- *
- * detach DLC from session and clean up
- */
-void
-rfcomm_dlc_close(struct rfcomm_dlc *dlc, int err)
-{
-	struct rfcomm_session *rs;
-	struct rfcomm_credit *credit;
-
-	KKASSERT(dlc->rd_state != RFCOMM_DLC_CLOSED);
-
-	/* Clear credit history */
-	rs = dlc->rd_session;
-	STAILQ_FOREACH(credit, &rs->rs_credits, rc_next)
-		if (credit->rc_dlc == dlc)
-			credit->rc_dlc = NULL;
-
-	callout_stop(&dlc->rd_timeout);
-
-	LIST_REMOVE(dlc, rd_next);
-	dlc->rd_session = NULL;
-	dlc->rd_state = RFCOMM_DLC_CLOSED;
-
-	(*dlc->rd_proto->disconnected)(dlc->rd_upper, err);
-
-	/*
-	 * It is the responsibility of the party who sends the last
-	 * DISC(dlci) to disconnect the session, but we will schedule
-	 * an expiry just in case that doesnt happen..
-	 */
-	if (LIST_EMPTY(&rs->rs_dlcs)) {
-		if (rs->rs_state == RFCOMM_SESSION_LISTEN)
-			rfcomm_session_free(rs);
-		else
-			callout_reset(&rs->rs_timeout, rfcomm_ack_timeout * hz,
-			    rfcomm_session_timeout, rs);
-	}
-}
-
-/*
- * rfcomm_dlc_timeout(dlc)
- *
- * DLC timeout function is schedUled when we sent any of SABM,
- * DISC, MCC_MSC, or MCC_PN and should be cancelled when we get
- * the relevant response. There is nothing to do but shut this
- * DLC down.
- */
-void
-rfcomm_dlc_timeout(void *arg)
-{
-	struct rfcomm_dlc *dlc = arg;
-
-	crit_enter();
-
-	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
-		rfcomm_dlc_close(dlc, ETIMEDOUT);
-	else if (dlc->rd_flags & RFCOMM_DLC_DETACH)
-		kfree(dlc, M_BLUETOOTH);
-
-	crit_exit();
-}
-
-/*
- * rfcomm_dlc_setmode(rfcomm_dlc)
- *
- * Set link mode for DLC.  This is only called when the session is
- * already open, so we don't need to worry about any previous mode
- * settings.
- */
-int
-rfcomm_dlc_setmode(struct rfcomm_dlc *dlc)
-{
-	int mode = 0;
-
-	KKASSERT(dlc->rd_session != NULL);
-	KKASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN);
-
-	DPRINTF("dlci %d, auth %s, encrypt %s, secure %s\n", dlc->rd_dlci,
-		(dlc->rd_mode & RFCOMM_LM_AUTH ? "yes" : "no"),
-		(dlc->rd_mode & RFCOMM_LM_ENCRYPT ? "yes" : "no"),
-		(dlc->rd_mode & RFCOMM_LM_SECURE ? "yes" : "no"));
-
-	if (dlc->rd_mode & RFCOMM_LM_AUTH)
-		mode |= L2CAP_LM_AUTH;
-
-	if (dlc->rd_mode & RFCOMM_LM_ENCRYPT)
-		mode |= L2CAP_LM_ENCRYPT;
-
-	if (dlc->rd_mode & RFCOMM_LM_SECURE)
-		mode |= L2CAP_LM_SECURE;
-
-	return l2cap_setopt(dlc->rd_session->rs_l2cap, SO_L2CAP_LM, &mode);
-}
-
-/*
- * rfcomm_dlc_connect(rfcomm_dlc)
- *
- * initiate DLC connection (session is already connected)
- */
-int
-rfcomm_dlc_connect(struct rfcomm_dlc *dlc)
-{
-	struct rfcomm_mcc_pn pn;
-	int err = 0;
-
-	KKASSERT(dlc->rd_session != NULL);
-	KKASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN);
-	KKASSERT(dlc->rd_state == RFCOMM_DLC_WAIT_SESSION);
-
-	/*
-	 * If we have not already sent a PN on the session, we must send
-	 * a PN to negotiate Credit Flow Control, and this setting will
-	 * apply to all future connections for this session. We ask for
-	 * this every time, in order to establish initial credits.
-	 */
-	memset(&pn, 0, sizeof(pn));
-	pn.dlci = dlc->rd_dlci;
-	pn.priority = dlc->rd_dlci | 0x07;
-	pn.mtu = htole16(dlc->rd_mtu);
-
-	pn.flow_control = 0xf0;
-	dlc->rd_rxcred = (dlc->rd_rxsize / dlc->rd_mtu);
-	dlc->rd_rxcred = min(dlc->rd_rxcred, RFCOMM_CREDITS_DEFAULT);
-	pn.credits = dlc->rd_rxcred;
-
-	err = rfcomm_session_send_mcc(dlc->rd_session, 1,
-					RFCOMM_MCC_PN, &pn, sizeof(pn));
-	if (err)
-		return err;
-
-	dlc->rd_state = RFCOMM_DLC_WAIT_CONNECT;
-	callout_reset(&dlc->rd_timeout, rfcomm_mcc_timeout * hz,
-	    rfcomm_dlc_timeout, dlc);
-	return 0;
-}
-
-/*
- * rfcomm_dlc_open(rfcomm_dlc)
- *
- * send "Modem Status Command" and mark DLC as open.
- */
-int
-rfcomm_dlc_open(struct rfcomm_dlc *dlc)
-{
-	struct rfcomm_mcc_msc msc;
-	int err;
-
-	KKASSERT(dlc->rd_session != NULL);
-	KKASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN);
-
-	memset(&msc, 0, sizeof(msc));
-	msc.address = RFCOMM_MKADDRESS(1, dlc->rd_dlci);
-	msc.modem = dlc->rd_lmodem & 0xfe;	/* EA = 0 */
-	msc.brk =	0x00	   | 0x01;	/* EA = 1 */
-
-	err = rfcomm_session_send_mcc(dlc->rd_session, 1,
-				RFCOMM_MCC_MSC, &msc, sizeof(msc));
-	if (err)
-		return err;
-
-	callout_reset(&dlc->rd_timeout, rfcomm_mcc_timeout * hz,
-	    rfcomm_dlc_timeout, dlc);
-
-	dlc->rd_state = RFCOMM_DLC_OPEN;
-	(*dlc->rd_proto->connected)(dlc->rd_upper);
-
-	return 0;
-}
-
-/*
- * rfcomm_dlc_start(rfcomm_dlc)
- *
- * Start sending data (and/or credits) for DLC. Our strategy is to
- * send anything we can down to the l2cap layer. When credits run
- * out, data will naturally bunch up. When not using credit flow
- * control, we limit the number of packets we have pending to reduce
- * flow control lag.
- * We should deal with channel priority somehow.
- */
-void
-rfcomm_dlc_start(struct rfcomm_dlc *dlc)
-{
-	struct rfcomm_session *rs = dlc->rd_session;
-	struct mbuf *m;
-	int len, credits;
-
-	KKASSERT(rs != NULL);
-	KKASSERT(rs->rs_state == RFCOMM_SESSION_OPEN);
-	KKASSERT(dlc->rd_state == RFCOMM_DLC_OPEN);
-
-	for (;;) {
-		credits = 0;
-		len = dlc->rd_mtu;
-		if (rs->rs_flags & RFCOMM_SESSION_CFC) {
-			credits = (dlc->rd_rxsize / dlc->rd_mtu);
-			credits -= dlc->rd_rxcred;
-			credits = min(credits, RFCOMM_CREDITS_MAX);
-
-			if (credits > 0)
-				len--;
-
-			if (dlc->rd_txcred == 0)
-				len = 0;
-		} else {
-			if (rs->rs_flags & RFCOMM_SESSION_RFC)
-				break;
-
-			if (dlc->rd_rmodem & RFCOMM_MSC_FC)
-				break;
-
-			if (dlc->rd_pending > RFCOMM_CREDITS_DEFAULT)
-				break;
-		}
-
-		if (dlc->rd_txbuf == NULL)
-			len = 0;
-
-		if (len == 0) {
-			if (credits == 0)
-				break;
-
-			/*
-			 * No need to send small numbers of credits on their
-			 * own unless the other end hasn't many left.
-			 */
-			if (credits < RFCOMM_CREDITS_DEFAULT
-			    && dlc->rd_rxcred > RFCOMM_CREDITS_DEFAULT)
-				break;
-
-			m = NULL;
-		} else {
-			/*
-			 * take what data we can from (front of) txbuf
-			 */
-			m = dlc->rd_txbuf;
-			if (len < m->m_pkthdr.len) {
-				dlc->rd_txbuf = m_split(m, len, M_NOWAIT);
-				if (dlc->rd_txbuf == NULL) {
-					dlc->rd_txbuf = m;
-					break;
-				}
-			} else {
-				dlc->rd_txbuf = NULL;
-				len = m->m_pkthdr.len;
-			}
-		}
-
-		DPRINTFN(10, "dlci %d send %d bytes, %d credits, rxcred = %d\n",
-			dlc->rd_dlci, len, credits, dlc->rd_rxcred);
-
-		if (rfcomm_session_send_uih(rs, dlc, credits, m)) {
-			kprintf("%s: lost %d bytes on DLCI %d\n",
-				__func__, len, dlc->rd_dlci);
-
-			break;
-		}
-
-		dlc->rd_pending++;
-
-		if (rs->rs_flags & RFCOMM_SESSION_CFC) {
-			if (len > 0)
-				dlc->rd_txcred--;
-
-			if (credits > 0)
-				dlc->rd_rxcred += credits;
-		}
-	}
-}
diff --git a/sys/netbt/rfcomm_session.c b/sys/netbt/rfcomm_session.c
deleted file mode 100644
index 135105336d..0000000000
--- a/sys/netbt/rfcomm_session.c
+++ /dev/null
@@ -1,1697 +0,0 @@
-/* $OpenBSD: src/sys/netbt/rfcomm_session.c,v 1.3 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: rfcomm_session.c,v 1.12 2008/01/31 19:30:23 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/systm.h>
-#include <sys/types.h>
-#include <sys/endian.h>
-
-#include <net/if.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-#include <netbt/rfcomm.h>
-
-/******************************************************************************
- *
- * RFCOMM Multiplexer Sessions sit directly on L2CAP channels, and can
- * multiplex up to 30 incoming and 30 outgoing connections.
- * Only one Multiplexer is allowed between any two devices.
- */
-
-static void rfcomm_session_recv_sabm(struct rfcomm_session *, int);
-static void rfcomm_session_recv_disc(struct rfcomm_session *, int);
-static void rfcomm_session_recv_ua(struct rfcomm_session *, int);
-static void rfcomm_session_recv_dm(struct rfcomm_session *, int);
-static void rfcomm_session_recv_uih(struct rfcomm_session *, int, int, struct mbuf *, int);
-static void rfcomm_session_recv_mcc(struct rfcomm_session *, struct mbuf *);
-static void rfcomm_session_recv_mcc_test(struct rfcomm_session *, int, struct mbuf *);
-static void rfcomm_session_recv_mcc_fcon(struct rfcomm_session *, int);
-static void rfcomm_session_recv_mcc_fcoff(struct rfcomm_session *, int);
-static void rfcomm_session_recv_mcc_msc(struct rfcomm_session *, int, struct mbuf *);
-static void rfcomm_session_recv_mcc_rpn(struct rfcomm_session *, int, struct mbuf *);
-static void rfcomm_session_recv_mcc_rls(struct rfcomm_session *, int, struct mbuf *);
-static void rfcomm_session_recv_mcc_pn(struct rfcomm_session *, int, struct mbuf *);
-static void rfcomm_session_recv_mcc_nsc(struct rfcomm_session *, int, struct mbuf *);
-
-/* L2CAP callbacks */
-static void rfcomm_session_connecting(void *);
-static void rfcomm_session_connected(void *);
-static void rfcomm_session_disconnected(void *, int);
-static void *rfcomm_session_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
-static void rfcomm_session_complete(void *, int);
-static void rfcomm_session_linkmode(void *, int);
-static void rfcomm_session_input(void *, struct mbuf *);
-
-static const struct btproto rfcomm_session_proto = {
-	rfcomm_session_connecting,
-	rfcomm_session_connected,
-	rfcomm_session_disconnected,
-	rfcomm_session_newconn,
-	rfcomm_session_complete,
-	rfcomm_session_linkmode,
-	rfcomm_session_input,
-};
-
-struct rfcomm_session_list
-	rfcomm_session_active = LIST_HEAD_INITIALIZER(rfcomm_session_active);
-
-struct rfcomm_session_list
-	rfcomm_session_listen = LIST_HEAD_INITIALIZER(rfcomm_session_listen);
-
-vm_zone_t rfcomm_credit_pool;
-
-/*
- * RFCOMM System Parameters (see section 5.3)
- */
-int rfcomm_mtu_default = 127;	/* bytes */
-int rfcomm_ack_timeout = 20;	/* seconds */
-int rfcomm_mcc_timeout = 20;	/* seconds */
-
-/*
- * Reversed CRC table as per TS 07.10 Annex B.3.5
- */
-static const uint8_t crctable[256] = {	/* reversed, 8-bit, poly=0x07 */
-	0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
-	0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
-	0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
-	0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
-
-	0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
-	0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
-	0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
-	0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
-
-	0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
-	0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
-	0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
-	0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
-
-	0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
-	0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
-	0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
-	0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
-
-	0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
-	0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
-	0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
-	0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
-
-	0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
-	0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
-	0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
-	0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
-
-	0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
-	0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
-	0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
-	0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
-
-	0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
-	0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
-	0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
-	0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
-};
-
-#define FCS(f, d)	crctable[(f) ^ (d)]
-
-/*
- * rfcomm_init()
- *
- * initialize the "credit pool".
- */
-void
-rfcomm_init(void)
-{
-	rfcomm_credit_pool = zinit("rfcomm_credit",
-				   sizeof(struct rfcomm_credit),
-				   0, 0);
-}
-
-/*
- * rfcomm_session_alloc(list, sockaddr)
- *
- * allocate a new session and fill in the blanks, then
- * attach session to front of specified list (active or listen)
- */
-struct rfcomm_session *
-rfcomm_session_alloc(struct rfcomm_session_list *list,
-			struct sockaddr_bt *laddr)
-{
-	struct rfcomm_session *rs;
-	int err;
-
-	rs = kmalloc(sizeof(*rs), M_BLUETOOTH, M_NOWAIT | M_ZERO);
-	if (rs == NULL)
-		return NULL;
-
-	rs->rs_state = RFCOMM_SESSION_CLOSED;
-
-	callout_init(&rs->rs_timeout);
-
-	STAILQ_INIT(&rs->rs_credits);
-	LIST_INIT(&rs->rs_dlcs);
-
-	err = l2cap_attach(&rs->rs_l2cap, &rfcomm_session_proto, rs);
-	if (err) {
-		kfree(rs, M_BLUETOOTH);
-		return NULL;
-	}
-
-	(void)l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
-
-	if (laddr->bt_psm == L2CAP_PSM_ANY)
-		laddr->bt_psm = L2CAP_PSM_RFCOMM;
-
-	(void)l2cap_bind(rs->rs_l2cap, laddr);
-
-	LIST_INSERT_HEAD(list, rs, rs_next);
-
-	return rs;
-}
-
-/*
- * rfcomm_session_free(rfcomm_session)
- *
- * release a session, including any cleanup
- */
-void
-rfcomm_session_free(struct rfcomm_session *rs)
-{
-	struct rfcomm_credit *credit;
-
-	KKASSERT(rs != NULL);
-	KKASSERT(LIST_EMPTY(&rs->rs_dlcs));
-
-	rs->rs_state = RFCOMM_SESSION_CLOSED;
-
-	/*
-	 * If the callout is already invoked we have no way to stop it,
-	 * but it will call us back right away (there are no DLC's) so
-	 * not to worry.
-	 */
-	callout_stop(&rs->rs_timeout);
-	if (callout_active(&rs->rs_timeout))
-		return;
-
-	/*
-	 * Take care that rfcomm_session_disconnected() doesnt call
-	 * us back either as it will do if the l2cap_channel has not
-	 * been closed when we detach it..
-	 */
-	if (rs->rs_flags & RFCOMM_SESSION_FREE)
-		return;
-
-	rs->rs_flags |= RFCOMM_SESSION_FREE;
-
-	/* throw away any remaining credit notes */
-	while ((credit = STAILQ_FIRST(&rs->rs_credits)) != NULL) {
-		STAILQ_REMOVE_HEAD(&rs->rs_credits, rc_next);
-		zfree(rfcomm_credit_pool, credit);
-	}
-
-	KKASSERT(STAILQ_EMPTY(&rs->rs_credits));
-
-	/* Goodbye! */
-	LIST_REMOVE(rs, rs_next);
-	l2cap_detach(&rs->rs_l2cap);
-	kfree(rs, M_BLUETOOTH);
-}
-
-/*
- * rfcomm_session_lookup(sockaddr, sockaddr)
- *
- * Find active rfcomm session matching src and dest addresses
- * when src is BDADDR_ANY match any local address
- */
-struct rfcomm_session *
-rfcomm_session_lookup(struct sockaddr_bt *src, struct sockaddr_bt *dest)
-{
-	struct rfcomm_session *rs;
-	struct sockaddr_bt addr;
-
-	LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
-		if (rs->rs_state == RFCOMM_SESSION_CLOSED)
-			continue;
-
-		l2cap_sockaddr(rs->rs_l2cap, &addr);
-
-		if (bdaddr_same(&src->bt_bdaddr, &addr.bt_bdaddr) == 0)
-			if (bdaddr_any(&src->bt_bdaddr) == 0)
-				continue;
-
-		l2cap_peeraddr(rs->rs_l2cap, &addr);
-
-		if (addr.bt_psm != dest->bt_psm)
-			continue;
-
-		if (bdaddr_same(&dest->bt_bdaddr, &addr.bt_bdaddr))
-			break;
-	}
-
-	return rs;
-}
-
-/*
- * rfcomm_session_timeout(rfcomm_session)
- *
- * Session timeouts are scheduled when a session is left or
- * created with no DLCs, and when SABM(0) or DISC(0) are
- * sent.
- *
- * So, if it is in an open state with DLC's attached then
- * we leave it alone, otherwise the session is lost.
- */
-void
-rfcomm_session_timeout(void *arg)
-{
-	struct rfcomm_session *rs = arg;
-	struct rfcomm_dlc *dlc;
-
-	KKASSERT(rs != NULL);
-
-	crit_enter();
-
-	if (rs->rs_state != RFCOMM_SESSION_OPEN) {
-		DPRINTF("timeout\n");
-		rs->rs_state = RFCOMM_SESSION_CLOSED;
-
-		while (!LIST_EMPTY(&rs->rs_dlcs)) {
-			dlc = LIST_FIRST(&rs->rs_dlcs);
-
-			rfcomm_dlc_close(dlc, ETIMEDOUT);
-		}
-	}
-
-	if (LIST_EMPTY(&rs->rs_dlcs)) {
-		DPRINTF("expiring\n");
-		rfcomm_session_free(rs);
-	}
-	crit_exit();
-}
-
-/***********************************************************************
- *
- *	RFCOMM Session L2CAP protocol callbacks
- *
- */
-
-static void
-rfcomm_session_connecting(void *arg)
-{
-	/* struct rfcomm_session *rs = arg; */
-
-	DPRINTF("Connecting\n");
-}
-
-static void
-rfcomm_session_connected(void *arg)
-{
-	struct rfcomm_session *rs = arg;
-
-	DPRINTF("Connected\n");
-
-	/*
-	 * L2CAP is open.
-	 *
-	 * If we are initiator, we can send our SABM(0)
-	 * a timeout should be active?
-	 *
-	 * We must take note of the L2CAP MTU because currently
-	 * the L2CAP implementation can only do Basic Mode.
-	 */
-	l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
-
-	rs->rs_mtu -= 6; /* (RFCOMM overhead could be this big) */
-	if (rs->rs_mtu < RFCOMM_MTU_MIN) {
-		rfcomm_session_disconnected(rs, EINVAL);
-		return;
-	}
-
-	if (IS_INITIATOR(rs)) {
-		int err;
-
-		err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, 0);
-		if (err)
-			rfcomm_session_disconnected(rs, err);
-
-		callout_reset(&rs->rs_timeout, rfcomm_ack_timeout * hz,
-		    rfcomm_session_timeout, rs);
-	}
-}
-
-static void
-rfcomm_session_disconnected(void *arg, int err)
-{
-	struct rfcomm_session *rs = arg;
-	struct rfcomm_dlc *dlc;
-
-	DPRINTF("Disconnected\n");
-
-	rs->rs_state = RFCOMM_SESSION_CLOSED;
-
-	while (!LIST_EMPTY(&rs->rs_dlcs)) {
-		dlc = LIST_FIRST(&rs->rs_dlcs);
-
-		rfcomm_dlc_close(dlc, err);
-	}
-
-	rfcomm_session_free(rs);
-}
-
-static void *
-rfcomm_session_newconn(void *arg, struct sockaddr_bt *laddr,
-				struct sockaddr_bt *raddr)
-{
-	struct rfcomm_session *new, *rs = arg;
-
-	DPRINTF("New Connection\n");
-
-	/*
-	 * Incoming session connect request. We should return a new
-	 * session pointer if this is acceptable. The L2CAP layer
-	 * passes local and remote addresses, which we must check as
-	 * only one RFCOMM session is allowed between any two devices
-	 */
-	new = rfcomm_session_lookup(laddr, raddr);
-	if (new != NULL)
-		return NULL;
-
-	new = rfcomm_session_alloc(&rfcomm_session_active, laddr);
-	if (new == NULL)
-		return NULL;
-
-	new->rs_mtu = rs->rs_mtu;
-	new->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
-
-	/*
-	 * schedule an expiry so that if nothing comes of it we
-	 * can punt.
-	 */
-	callout_reset(&rs->rs_timeout, rfcomm_mcc_timeout * hz,
-	    rfcomm_session_timeout, rs);
-
-	return new->rs_l2cap;
-}
-
-static void
-rfcomm_session_complete(void *arg, int count)
-{
-	struct rfcomm_session *rs = arg;
-	struct rfcomm_credit *credit;
-	struct rfcomm_dlc *dlc;
-
-	/*
-	 * count L2CAP packets are 'complete', meaning that they are cleared
-	 * our buffers (for best effort) or arrived safe (for guaranteed) so
-	 * we can take it off our list and pass the message on, so that
-	 * eventually the data can be removed from the sockbuf
-	 */
-	while (count-- > 0) {
-		credit = STAILQ_FIRST(&rs->rs_credits);
-#ifdef DIAGNOSTIC
-		if (credit == NULL) {
-			kprintf("%s: too many packets completed!\n", __func__);
-			break;
-		}
-#endif
-		dlc = credit->rc_dlc;
-		if (dlc != NULL) {
-			dlc->rd_pending--;
-			(*dlc->rd_proto->complete)
-					(dlc->rd_upper, credit->rc_len);
-
-			/*
-			 * if not using credit flow control, we may push
-			 * more data now
-			 */
-			if ((rs->rs_flags & RFCOMM_SESSION_CFC) == 0
-			    && dlc->rd_state == RFCOMM_DLC_OPEN) {
-				rfcomm_dlc_start(dlc);
-			}
-
-			/*
-			 * When shutdown is indicated, we are just waiting to
-			 * clear outgoing data.
-			 */
-			if ((dlc->rd_flags & RFCOMM_DLC_SHUTDOWN)
-			    && dlc->rd_txbuf == NULL && dlc->rd_pending == 0) {
-				dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
-				rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
-							    dlc->rd_dlci);
-				callout_reset(&dlc->rd_timeout,
-				    rfcomm_ack_timeout * hz,
-				    rfcomm_dlc_timeout, dlc);
-			}
-		}
-
-		STAILQ_REMOVE_HEAD(&rs->rs_credits, rc_next);
-		zfree(rfcomm_credit_pool, credit);
-	}
-
-	/*
-	 * If session is closed, we are just waiting to clear the queue
-	 */
-	if (rs->rs_state == RFCOMM_SESSION_CLOSED) {
-		if (STAILQ_EMPTY(&rs->rs_credits))
-			l2cap_disconnect(rs->rs_l2cap, 0);
-	}
-}
-
-/*
- * Link Mode changed
- *
- * This is called when a mode change is complete. Proceed with connections
- * where appropriate, or pass the new mode to any active DLCs.
- */
-static void
-rfcomm_session_linkmode(void *arg, int new)
-{
-	struct rfcomm_session *rs = arg;
-	struct rfcomm_dlc *dlc, *next;
-	int err, mode = 0;
-
-	DPRINTF("auth %s, encrypt %s, secure %s\n",
-		(new & L2CAP_LM_AUTH ? "on" : "off"),
-		(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
-		(new & L2CAP_LM_SECURE ? "on" : "off"));
-
-	if (new & L2CAP_LM_AUTH)
-		mode |= RFCOMM_LM_AUTH;
-
-	if (new & L2CAP_LM_ENCRYPT)
-		mode |= RFCOMM_LM_ENCRYPT;
-
-	if (new & L2CAP_LM_SECURE)
-		mode |= RFCOMM_LM_SECURE;
-
-	next = LIST_FIRST(&rs->rs_dlcs);
-	while ((dlc = next) != NULL) {
-		next = LIST_NEXT(dlc, rd_next);
-
-		switch (dlc->rd_state) {
-		case RFCOMM_DLC_WAIT_SEND_SABM:	/* we are connecting */
-			if ((mode & dlc->rd_mode) != dlc->rd_mode) {
-				rfcomm_dlc_close(dlc, ECONNABORTED);
-			} else {
-				err = rfcomm_session_send_frame(rs,
-					    RFCOMM_FRAME_SABM, dlc->rd_dlci);
-				if (err) {
-					rfcomm_dlc_close(dlc, err);
-				} else {
-					dlc->rd_state = RFCOMM_DLC_WAIT_RECV_UA;
-					callout_reset(&dlc->rd_timeout,
-					    rfcomm_ack_timeout * hz,
-				    	    rfcomm_dlc_timeout, dlc);
-
-					break;
-				}
-			}
-
-			/*
-			 * If we aborted the connection and there are no more DLCs
-			 * on the session, it is our responsibility to disconnect.
-			 */
-			if (!LIST_EMPTY(&rs->rs_dlcs))
-				break;
-
-			rs->rs_state = RFCOMM_SESSION_WAIT_DISCONNECT;
-			rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, 0);
-			callout_reset(&rs->rs_timeout, rfcomm_ack_timeout * hz,
-			    rfcomm_session_timeout, rs);
-			break;
-
-		case RFCOMM_DLC_WAIT_SEND_UA: /* they are connecting */
-			if ((mode & dlc->rd_mode) != dlc->rd_mode) {
-				rfcomm_session_send_frame(rs,
-					    RFCOMM_FRAME_DM, dlc->rd_dlci);
-				rfcomm_dlc_close(dlc, ECONNABORTED);
-				break;
-			}
-
-			err = rfcomm_session_send_frame(rs,
-					    RFCOMM_FRAME_UA, dlc->rd_dlci);
-			if (err) {
-				rfcomm_session_send_frame(rs,
-						RFCOMM_FRAME_DM, dlc->rd_dlci);
-				rfcomm_dlc_close(dlc, err);
-				break;
-			}
-
-			err = rfcomm_dlc_open(dlc);
-			if (err) {
-				rfcomm_session_send_frame(rs,
-						RFCOMM_FRAME_DM, dlc->rd_dlci);
-				rfcomm_dlc_close(dlc, err);
-				break;
-			}
-
-			break;
-
-		case RFCOMM_DLC_WAIT_RECV_UA:
-		case RFCOMM_DLC_OPEN: /* already established */
-			(*dlc->rd_proto->linkmode)(dlc->rd_upper, mode);
-			break;
-
-		default:
-			break;
-		}
-	}
-}
-
-/*
- * Receive data from L2CAP layer for session. There is always exactly one
- * RFCOMM frame contained in each L2CAP frame.
- */
-static void
-rfcomm_session_input(void *arg, struct mbuf *m)
-{
-	struct rfcomm_session *rs = arg;
-	int dlci, len, type, pf;
-	uint8_t fcs, b;
-
-	KKASSERT(m != NULL);
-	KKASSERT(rs != NULL);
-
-	/*
-	 * UIH frames: FCS is only calculated on address and control fields
-	 * For other frames: FCS is calculated on address, control and length
-	 * Length may extend to two octets
-	 */
-	fcs = 0xff;
-
-	if (m->m_pkthdr.len < 4) {
-		DPRINTF("short frame (%d), discarded\n", m->m_pkthdr.len);
-		goto done;
-	}
-
-	/* address - one octet */
-	m_copydata(m, 0, 1, &b);
-	m_adj(m, 1);
-	fcs = FCS(fcs, b);
-	dlci = RFCOMM_DLCI(b);
-
-	/* control - one octet */
-	m_copydata(m, 0, 1, &b);
-	m_adj(m, 1);
-	fcs = FCS(fcs, b);
-	type = RFCOMM_TYPE(b);
-	pf = RFCOMM_PF(b);
-
-	/* length - may be two octets */
-	m_copydata(m, 0, 1, &b);
-	m_adj(m, 1);
-	if (type != RFCOMM_FRAME_UIH)
-		fcs = FCS(fcs, b);
-	len = (b >> 1) & 0x7f;
-
-	if (RFCOMM_EA(b) == 0) {
-		if (m->m_pkthdr.len < 2) {
-			DPRINTF("short frame (%d, EA = 0), discarded\n",
-				m->m_pkthdr.len);
-			goto done;
-		}
-
-		m_copydata(m, 0, 1, &b);
-		m_adj(m, 1);
-		if (type != RFCOMM_FRAME_UIH)
-			fcs = FCS(fcs, b);
-
-		len |= (b << 7);
-	}
-
-	/* FCS byte is last octet in frame */
-	m_copydata(m, m->m_pkthdr.len - 1, 1, &b);
-	m_adj(m, -1);
-	fcs = FCS(fcs, b);
-
-	if (fcs != 0xcf) {
-		DPRINTF("Bad FCS value (%#2.2x), frame discarded\n", fcs);
-		goto done;
-	}
-
-	DPRINTFN(10, "dlci %d, type %2.2x, len = %d\n", dlci, type, len);
-
-	switch (type) {
-	case RFCOMM_FRAME_SABM:
-		if (pf)
-			rfcomm_session_recv_sabm(rs, dlci);
-		break;
-
-	case RFCOMM_FRAME_DISC:
-		if (pf)
-			rfcomm_session_recv_disc(rs, dlci);
-		break;
-
-	case RFCOMM_FRAME_UA:
-		if (pf)
-			rfcomm_session_recv_ua(rs, dlci);
-		break;
-
-	case RFCOMM_FRAME_DM:
-		rfcomm_session_recv_dm(rs, dlci);
-		break;
-
-	case RFCOMM_FRAME_UIH:
-		rfcomm_session_recv_uih(rs, dlci, pf, m, len);
-		return;	/* (no release) */
-
-	default:
-		UNKNOWN(type);
-		break;
-	}
-
-done:
-	m_freem(m);
-}
-
-/***********************************************************************
- *
- *	RFCOMM Session receive processing
- */
-
-/*
- * rfcomm_session_recv_sabm(rfcomm_session, dlci)
- *
- * Set Asyncrhonous Balanced Mode - open the channel.
- */
-static void
-rfcomm_session_recv_sabm(struct rfcomm_session *rs, int dlci)
-{
-	struct rfcomm_dlc *dlc;
-	int err;
-
-	DPRINTFN(5, "SABM(%d)\n", dlci);
-
-	if (dlci == 0) {	/* Open Session */
-		rs->rs_state = RFCOMM_SESSION_OPEN;
-		rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, 0);
-		LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
-			if (dlc->rd_state == RFCOMM_DLC_WAIT_SESSION)
-				rfcomm_dlc_connect(dlc);
-		}
-		return;
-	}
-
-	if (rs->rs_state != RFCOMM_SESSION_OPEN) {
-		DPRINTF("session was not even open!\n");
-		return;
-	}
-
-	/* validate direction bit */
-	if ((IS_INITIATOR(rs) && !RFCOMM_DIRECTION(dlci))
-	    || (!IS_INITIATOR(rs) && RFCOMM_DIRECTION(dlci))) {
-		DPRINTF("Invalid direction bit on DLCI\n");
-		return;
-	}
-
-	/*
-	 * look for our DLC - this may exist if we received PN
-	 * already, or we may have to fabricate a new one.
-	 */
-	dlc = rfcomm_dlc_lookup(rs, dlci);
-	if (dlc == NULL) {
-		dlc = rfcomm_dlc_newconn(rs, dlci);
-		if (dlc == NULL)
-			return;	/* (DM is sent) */
-	}
-
-	/*
-	 * ..but if this DLC is not waiting to connect, they did
-	 * something wrong, ignore it.
-	 */
-	if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT)
-		return;
-
-	/* set link mode */
-	err = rfcomm_dlc_setmode(dlc);
-	if (err == EINPROGRESS) {
-		dlc->rd_state = RFCOMM_DLC_WAIT_SEND_UA;
-		(*dlc->rd_proto->connecting)(dlc->rd_upper);
-		return;
-	}
-	if (err)
-		goto close;
-
-	err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci);
-	if (err)
-		goto close;
-
-	/* and mark it open */
-	err = rfcomm_dlc_open(dlc);
-	if (err)
-		goto close;
-
-	return;
-
-close:
-	rfcomm_dlc_close(dlc, err);
-}
-
-/*
- * Receive Disconnect Command
- */
-static void
-rfcomm_session_recv_disc(struct rfcomm_session *rs, int dlci)
-{
-	struct rfcomm_dlc *dlc;
-
-	DPRINTFN(5, "DISC(%d)\n", dlci);
-
-	if (dlci == 0) {
-		/*
-		 * Disconnect Session
-		 *
-		 * We set the session state to CLOSED so that when
-		 * the UA frame is clear the session will be closed
-		 * automatically. We wont bother to close any DLC's
-		 * just yet as there should be none. In the unlikely
-		 * event that something is left, it will get flushed
-		 * out as the session goes down.
-		 */
-		rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, 0);
-		rs->rs_state = RFCOMM_SESSION_CLOSED;
-		return;
-	}
-
-	dlc = rfcomm_dlc_lookup(rs, dlci);
-	if (dlc == NULL) {
-		rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
-		return;
-	}
-
-	rfcomm_dlc_close(dlc, ECONNRESET);
-	rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci);
-}
-
-/*
- * Receive Unnumbered Acknowledgement Response
- *
- * This should be a response to a DISC or SABM frame that we
- * have previously sent. If unexpected, ignore it.
- */
-static void
-rfcomm_session_recv_ua(struct rfcomm_session *rs, int dlci)
-{
-	struct rfcomm_dlc *dlc;
-
-	DPRINTFN(5, "UA(%d)\n", dlci);
-
-	if (dlci == 0) {
-		switch (rs->rs_state) {
-		case RFCOMM_SESSION_WAIT_CONNECT:	/* We sent SABM */
-			callout_stop(&rs->rs_timeout);
-			rs->rs_state = RFCOMM_SESSION_OPEN;
-			LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
-				if (dlc->rd_state == RFCOMM_DLC_WAIT_SESSION)
-					rfcomm_dlc_connect(dlc);
-			}
-			break;
-
-		case RFCOMM_SESSION_WAIT_DISCONNECT:	/* We sent DISC */
-			callout_stop(&rs->rs_timeout);
-			rs->rs_state = RFCOMM_SESSION_CLOSED;
-			l2cap_disconnect(rs->rs_l2cap, 0);
-			break;
-
-		default:
-			DPRINTF("Received spurious UA(0)!\n");
-			break;
-		}
-
-		return;
-	}
-
-	/*
-	 * If we have no DLC on this dlci, we may have aborted
-	 * without shutting down properly, so check if the session
-	 * needs disconnecting.
-	 */
-	dlc = rfcomm_dlc_lookup(rs, dlci);
-	if (dlc == NULL)
-		goto check;
-
-	switch (dlc->rd_state) {
-	case RFCOMM_DLC_WAIT_RECV_UA:		/* We sent SABM */
-		rfcomm_dlc_open(dlc);
-		return;
-
-	case RFCOMM_DLC_WAIT_DISCONNECT:	/* We sent DISC */
-		rfcomm_dlc_close(dlc, 0);
-		break;
-
-	default:
-		DPRINTF("Received spurious UA(%d)!\n", dlci);
-		return;
-	}
-
-check:	/* last one out turns out the light */
-	if (LIST_EMPTY(&rs->rs_dlcs)) {
-		rs->rs_state = RFCOMM_SESSION_WAIT_DISCONNECT;
-		rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, 0);
-		callout_reset(&rs->rs_timeout, rfcomm_ack_timeout*hz,rfcomm_session_timeout,rs);
-	}
-}
-
-/*
- * Receive Disconnected Mode Response
- *
- * If this does not apply to a known DLC then we may ignore it.
- */
-static void
-rfcomm_session_recv_dm(struct rfcomm_session *rs, int dlci)
-{
-	struct rfcomm_dlc *dlc;
-
-	DPRINTFN(5, "DM(%d)\n", dlci);
-
-	dlc = rfcomm_dlc_lookup(rs, dlci);
-	if (dlc == NULL)
-		return;
-
-	if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT)
-		rfcomm_dlc_close(dlc, ECONNREFUSED);
-	else
-		rfcomm_dlc_close(dlc, ECONNRESET);
-}
-
-/*
- * Receive Unnumbered Information with Header check (MCC or data packet)
- */
-static void
-rfcomm_session_recv_uih(struct rfcomm_session *rs, int dlci,
-			int pf, struct mbuf *m, int len)
-{
-	struct rfcomm_dlc *dlc;
-	uint8_t credits = 0;
-
-	DPRINTFN(10, "UIH(%d)\n", dlci);
-
-	if (dlci == 0) {
-		rfcomm_session_recv_mcc(rs, m);
-		return;
-	}
-
-	if (m->m_pkthdr.len != len + pf) {
-		DPRINTF("Bad Frame Length (%d), frame discarded\n",
-			    m->m_pkthdr.len);
-
-		goto discard;
-	}
-
-	dlc = rfcomm_dlc_lookup(rs, dlci);
-	if (dlc == NULL) {
-		DPRINTF("UIH received for non existent DLC, discarded\n");
-		rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
-		goto discard;
-	}
-
-	if (dlc->rd_state != RFCOMM_DLC_OPEN) {
-		DPRINTF("non-open DLC (state = %d), discarded\n",
-				dlc->rd_state);
-		goto discard;
-	}
-
-	/* if PF is set, credits were included */
-	if (rs->rs_flags & RFCOMM_SESSION_CFC) {
-		if (pf != 0) {
-			if (m->m_pkthdr.len < sizeof(credits)) {
-				DPRINTF("Bad PF value, UIH discarded\n");
-				goto discard;
-			}
-
-			m_copydata(m, 0, sizeof(credits), &credits);
-			m_adj(m, sizeof(credits));
-
-			dlc->rd_txcred += credits;
-
-			if (credits > 0 && dlc->rd_txbuf != NULL)
-				rfcomm_dlc_start(dlc);
-		}
-
-		if (len == 0)
-			goto discard;
-
-		if (dlc->rd_rxcred == 0) {
-			DPRINTF("Credit limit reached, UIH discarded\n");
-			goto discard;
-		}
-
-		if (len > dlc->rd_rxsize) {
-			DPRINTF("UIH frame exceeds rxsize, discarded\n");
-			goto discard;
-		}
-
-		dlc->rd_rxcred--;
-		dlc->rd_rxsize -= len;
-	}
-
-	(*dlc->rd_proto->input)(dlc->rd_upper, m);
-	return;
-
-discard:
-	m_freem(m);
-}
-
-/*
- * Receive Multiplexer Control Command
- */
-static void
-rfcomm_session_recv_mcc(struct rfcomm_session *rs, struct mbuf *m)
-{
-	int type, cr, len;
-	uint8_t b;
-
-	/*
-	 * Extract MCC header.
-	 *
-	 * Fields are variable length using extension bit = 1 to signify the
-	 * last octet in the sequence.
-	 *
-	 * Only single octet types are defined in TS 07.10/RFCOMM spec
-	 *
-	 * Length can realistically only use 15 bits (max RFCOMM MTU)
-	 */
-	if (m->m_pkthdr.len < sizeof(b)) {
-		DPRINTF("Short MCC header, discarded\n");
-		goto release;
-	}
-
-	m_copydata(m, 0, sizeof(b), &b);
-	m_adj(m, sizeof(b));
-
-	if (RFCOMM_EA(b) == 0) {	/* verify no extensions */
-		DPRINTF("MCC type EA = 0, discarded\n");
-		goto release;
-	}
-
-	type = RFCOMM_MCC_TYPE(b);
-	cr = RFCOMM_CR(b);
-
-	len = 0;
-	do {
-		if (m->m_pkthdr.len < sizeof(b)) {
-			DPRINTF("Short MCC header, discarded\n");
-			goto release;
-		}
-
-		m_copydata(m, 0, sizeof(b), &b);
-		m_adj(m, sizeof(b));
-
-		len = (len << 7) | (b >> 1);
-		len = min(len, RFCOMM_MTU_MAX);
-	} while (RFCOMM_EA(b) == 0);
-
-	if (len != m->m_pkthdr.len) {
-		DPRINTF("Incorrect MCC length, discarded\n");
-		goto release;
-	}
-
-	DPRINTFN(2, "MCC %s type %2.2x (%d bytes)\n",
-		(cr ? "command" : "response"), type, len);
-
-	/*
-	 * pass to command handler
-	 */
-	switch(type) {
-	case RFCOMM_MCC_TEST:	/* Test */
-		rfcomm_session_recv_mcc_test(rs, cr, m);
-		break;
-
-	case RFCOMM_MCC_FCON:	/* Flow Control On */
-		rfcomm_session_recv_mcc_fcon(rs, cr);
-		break;
-
-	case RFCOMM_MCC_FCOFF:	/* Flow Control Off */
-		rfcomm_session_recv_mcc_fcoff(rs, cr);
-		break;
-
-	case RFCOMM_MCC_MSC:	/* Modem Status Command */
-		rfcomm_session_recv_mcc_msc(rs, cr, m);
-		break;
-
-	case RFCOMM_MCC_RPN:	/* Remote Port Negotiation */
-		rfcomm_session_recv_mcc_rpn(rs, cr, m);
-		break;
-
-	case RFCOMM_MCC_RLS:	/* Remote Line Status */
-		rfcomm_session_recv_mcc_rls(rs, cr, m);
-		break;
-
-	case RFCOMM_MCC_PN:	/* Parameter Negotiation */
-		rfcomm_session_recv_mcc_pn(rs, cr, m);
-		break;
-
-	case RFCOMM_MCC_NSC:	/* Non Supported Command */
-		rfcomm_session_recv_mcc_nsc(rs, cr, m);
-		break;
-
-	default:
-		b = RFCOMM_MKMCC_TYPE(cr, type);
-		rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_NSC, &b, sizeof(b));
-	}
-
-release:
-	m_freem(m);
-}
-
-/*
- * process TEST command/response
- */
-static void
-rfcomm_session_recv_mcc_test(struct rfcomm_session *rs, int cr, struct mbuf *m)
-{
-	void *data;
-	int len;
-
-	if (cr == 0)	/* ignore ack */
-		return;
-
-	/*
-	 * we must send all the data they included back as is
-	 */
-
-	len = m->m_pkthdr.len;
-	if (len > RFCOMM_MTU_MAX)
-		return;
-
-	data = kmalloc(len, M_BLUETOOTH, M_NOWAIT);
-	if (data == NULL)
-		return;
-
-	m_copydata(m, 0, len, data);
-	rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_TEST, data, len);
-	kfree(data, M_BLUETOOTH);
-}
-
-/*
- * process Flow Control ON command/response
- */
-static void
-rfcomm_session_recv_mcc_fcon(struct rfcomm_session *rs, int cr)
-{
-
-	if (cr == 0)	/* ignore ack */
-		return;
-
-	rs->rs_flags |= RFCOMM_SESSION_RFC;
-	rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_FCON, NULL, 0);
-}
-
-/*
- * process Flow Control OFF command/response
- */
-static void
-rfcomm_session_recv_mcc_fcoff(struct rfcomm_session *rs, int cr)
-{
-	if (cr == 0)	/* ignore ack */
-		return;
-
-	rs->rs_flags &= ~RFCOMM_SESSION_RFC;
-	rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_FCOFF, NULL, 0);
-}
-
-/*
- * process Modem Status Command command/response
- */
-static void
-rfcomm_session_recv_mcc_msc(struct rfcomm_session *rs, int cr, struct mbuf *m)
-{
-	struct rfcomm_mcc_msc msc;	/* (3 octets) */
-	struct rfcomm_dlc *dlc;
-	int len = 0;
-
-	/* [ADDRESS] */
-	if (m->m_pkthdr.len < sizeof(msc.address))
-		return;
-
-	m_copydata(m, 0, sizeof(msc.address), &msc.address);
-	m_adj(m, sizeof(msc.address));
-	len += sizeof(msc.address);
-
-	dlc = rfcomm_dlc_lookup(rs, RFCOMM_DLCI(msc.address));
-
-	if (cr == 0) {	/* ignore acks */
-		if (dlc != NULL)
-			callout_stop(&dlc->rd_timeout);
-
-		return;
-	}
-
-	if (dlc == NULL) {
-		rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM,
-						RFCOMM_DLCI(msc.address));
-		return;
-	}
-
-	/* [SIGNALS] */
-	if (m->m_pkthdr.len < sizeof(msc.modem))
-		return;
-
-	m_copydata(m, 0, sizeof(msc.modem), &msc.modem);
-	m_adj(m, sizeof(msc.modem));
-	len += sizeof(msc.modem);
-
-	dlc->rd_rmodem = msc.modem;
-	/* XXX how do we signal this upstream? */
-
-	if (RFCOMM_EA(msc.modem) == 0) {
-		if (m->m_pkthdr.len < sizeof(msc.brk))
-			return;
-
-		m_copydata(m, 0, sizeof(msc.brk), &msc.brk);
-		m_adj(m, sizeof(msc.brk));
-		len += sizeof(msc.brk);
-
-		/* XXX how do we signal this upstream? */
-	}
-
-	rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_MSC, &msc, len);
-}
-
-/*
- * process Remote Port Negotiation command/response
- */
-static void
-rfcomm_session_recv_mcc_rpn(struct rfcomm_session *rs, int cr, struct mbuf *m)
-{
-	struct rfcomm_mcc_rpn rpn;
-	uint16_t mask;
-
-	if (cr == 0)	/* ignore ack */
-		return;
-
-	/* default values */
-	rpn.bit_rate = RFCOMM_RPN_BR_9600;
-	rpn.line_settings = RFCOMM_RPN_8_N_1;
-	rpn.flow_control = RFCOMM_RPN_FLOW_NONE;
-	rpn.xon_char = RFCOMM_RPN_XON_CHAR;
-	rpn.xoff_char = RFCOMM_RPN_XOFF_CHAR;
-
-	if (m->m_pkthdr.len == sizeof(rpn)) {
-		m_copydata(m, 0, sizeof(rpn), (caddr_t)&rpn);
-		rpn.param_mask = RFCOMM_RPN_PM_ALL;
-	} else if (m->m_pkthdr.len == 1) {
-		m_copydata(m, 0, 1, (caddr_t)&rpn);
-		rpn.param_mask = letoh16(rpn.param_mask);
-	} else {
-		DPRINTF("Bad RPN length (%d)\n", m->m_pkthdr.len);
-		return;
-	}
-
-	mask = 0;
-
-	if (rpn.param_mask & RFCOMM_RPN_PM_RATE)
-		mask |= RFCOMM_RPN_PM_RATE;
-
-	if (rpn.param_mask & RFCOMM_RPN_PM_DATA
-	    && RFCOMM_RPN_DATA_BITS(rpn.line_settings) == RFCOMM_RPN_DATA_8)
-		mask |= RFCOMM_RPN_PM_DATA;
-
-	if (rpn.param_mask & RFCOMM_RPN_PM_STOP
-	    && RFCOMM_RPN_STOP_BITS(rpn.line_settings) == RFCOMM_RPN_STOP_1)
-		mask |= RFCOMM_RPN_PM_STOP;
-
-	if (rpn.param_mask & RFCOMM_RPN_PM_PARITY
-	    && RFCOMM_RPN_PARITY(rpn.line_settings) == RFCOMM_RPN_PARITY_NONE)
-		mask |= RFCOMM_RPN_PM_PARITY;
-
-	if (rpn.param_mask & RFCOMM_RPN_PM_XON
-	    && rpn.xon_char == RFCOMM_RPN_XON_CHAR)
-		mask |= RFCOMM_RPN_PM_XON;
-
-	if (rpn.param_mask & RFCOMM_RPN_PM_XOFF
-	    && rpn.xoff_char == RFCOMM_RPN_XOFF_CHAR)
-		mask |= RFCOMM_RPN_PM_XOFF;
-
-	if (rpn.param_mask & RFCOMM_RPN_PM_FLOW
-	    && rpn.flow_control == RFCOMM_RPN_FLOW_NONE)
-		mask |= RFCOMM_RPN_PM_FLOW;
-
-	rpn.param_mask = htole16(mask);
-
-	rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_RPN, &rpn, sizeof(rpn));
-}
-
-/*
- * process Remote Line Status command/response
- */
-static void
-rfcomm_session_recv_mcc_rls(struct rfcomm_session *rs, int cr, struct mbuf *m)
-{
-	struct rfcomm_mcc_rls rls;
-
-	if (cr == 0)	/* ignore ack */
-		return;
-
-	if (m->m_pkthdr.len != sizeof(rls)) {
-		DPRINTF("Bad RLS length %d\n", m->m_pkthdr.len);
-		return;
-	}
-
-	m_copydata(m, 0, sizeof(rls), (caddr_t)&rls);
-
-	/*
-	 * So far as I can tell, we just send back what
-	 * they sent us. This signifies errors that seem
-	 * irrelevent for RFCOMM over L2CAP.
-	 */
-	rls.address |= 0x03;	/* EA = 1, CR = 1 */
-	rls.status &= 0x0f;	/* only 4 bits valid */
-
-	rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_RLS, &rls, sizeof(rls));
-}
-
-/*
- * process Parameter Negotiation command/response
- */
-static void
-rfcomm_session_recv_mcc_pn(struct rfcomm_session *rs, int cr, struct mbuf *m)
-{
-	struct rfcomm_dlc *dlc;
-	struct rfcomm_mcc_pn pn;
-	int err;
-
-	if (m->m_pkthdr.len != sizeof(pn)) {
-		DPRINTF("Bad PN length %d\n", m->m_pkthdr.len);
-		return;
-	}
-
-	m_copydata(m, 0, sizeof(pn), (caddr_t)&pn);
-
-	pn.dlci &= 0x3f;
-	pn.mtu = letoh16(pn.mtu);
-
-	dlc = rfcomm_dlc_lookup(rs, pn.dlci);
-	if (cr) {	/* Command */
-		/*
-		 * If there is no DLC present, this is a new
-		 * connection so attempt to make one
-		 */
-		if (dlc == NULL) {
-			dlc = rfcomm_dlc_newconn(rs, pn.dlci);
-			if (dlc == NULL)
-				return;	/* (DM is sent) */
-		}
-
-		/* accept any valid MTU, and offer it back */
-		pn.mtu = min(pn.mtu, RFCOMM_MTU_MAX);
-		pn.mtu = min(pn.mtu, rs->rs_mtu);
-		pn.mtu = max(pn.mtu, RFCOMM_MTU_MIN);
-		dlc->rd_mtu = pn.mtu;
-		pn.mtu = htole16(pn.mtu);
-
-		/* credits are only set before DLC is open */
-		if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT
-		    && (pn.flow_control & 0xf0) == 0xf0) {
-			rs->rs_flags |= RFCOMM_SESSION_CFC;
-			dlc->rd_txcred = pn.credits & 0x07;
-
-			dlc->rd_rxcred = (dlc->rd_rxsize / dlc->rd_mtu);
-			dlc->rd_rxcred = min(dlc->rd_rxcred,
-						RFCOMM_CREDITS_DEFAULT);
-
-			pn.flow_control = 0xe0;
-			pn.credits = dlc->rd_rxcred;
-		} else {
-			pn.flow_control = 0x00;
-			pn.credits = 0x00;
-		}
-
-		/* unused fields must be ignored and set to zero */
-		pn.ack_timer = 0;
-		pn.max_retrans = 0;
-
-		/* send our response */
-		err = rfcomm_session_send_mcc(rs, 0,
-					RFCOMM_MCC_PN, &pn, sizeof(pn));
-		if (err)
-			goto close;
-
-	} else {	/* Response */
-		/* ignore responses with no matching DLC */
-		if (dlc == NULL)
-			return;
-
-		callout_stop(&dlc->rd_timeout);
-
-		if (pn.mtu > RFCOMM_MTU_MAX || pn.mtu > dlc->rd_mtu) {
-			dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
-			err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
-							pn.dlci);
-			if (err)
-				goto close;
-
-			callout_reset(&dlc->rd_timeout, rfcomm_ack_timeout * hz,
-				    rfcomm_dlc_timeout, dlc);
-			return;
-		}
-		dlc->rd_mtu = pn.mtu;
-
-		/* if DLC is not waiting to connect, we are done */
-		if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT)
-			return;
-
-		/* set initial credits according to RFCOMM spec */
-		if ((pn.flow_control & 0xf0) == 0xe0) {
-			rs->rs_flags |= RFCOMM_SESSION_CFC;
-			dlc->rd_txcred = (pn.credits & 0x07);
-		}
-
-		callout_reset(&dlc->rd_timeout, rfcomm_ack_timeout * hz,
-				    rfcomm_dlc_timeout, dlc);
-
-		/* set link mode */
-		err = rfcomm_dlc_setmode(dlc);
-		if (err == EINPROGRESS) {
-			dlc->rd_state = RFCOMM_DLC_WAIT_SEND_SABM;
-			(*dlc->rd_proto->connecting)(dlc->rd_upper);
-			return;
-		}
-		if (err)
-			goto close;
-
-		/* we can proceed now */
-		err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, pn.dlci);
-		if (err)
-			goto close;
-
-		dlc->rd_state = RFCOMM_DLC_WAIT_RECV_UA;
-	}
-	return;
-
-close:
-	rfcomm_dlc_close(dlc, err);
-}
-
-/*
- * process Non Supported Command command/response
- */
-static void
-rfcomm_session_recv_mcc_nsc(struct rfcomm_session *rs,
-    int cr, struct mbuf *m)
-{
-	struct rfcomm_dlc *dlc, *next;
-
-	/*
-	 * Since we did nothing that is not mandatory,
-	 * we just abort the whole session..
-	 */
-
-	next = LIST_FIRST(&rs->rs_dlcs);
-	while ((dlc = next) != NULL) {
-		next = LIST_NEXT(dlc, rd_next);
-		rfcomm_dlc_close(dlc, ECONNABORTED);
-	}
-
-	rfcomm_session_free(rs);
-}
-
-/***********************************************************************
- *
- *	RFCOMM Session outward frame/uih/mcc building
- */
-
-/*
- * SABM/DISC/DM/UA frames are all minimal and mostly identical.
- */
-int
-rfcomm_session_send_frame(struct rfcomm_session *rs, int type, int dlci)
-{
-	struct rfcomm_cmd_hdr *hdr;
-	struct rfcomm_credit *credit;
-	struct mbuf *m;
-	uint8_t fcs, cr;
-
-	credit = zalloc(rfcomm_credit_pool);
-	if (credit == NULL)
-		return ENOMEM;
-
-	m = m_gethdr(M_NOWAIT, MT_DATA);
-	if (m == NULL) {
-		zfree(rfcomm_credit_pool, credit);
-		return ENOMEM;
-	}
-
-	/*
-	 * The CR (command/response) bit identifies the frame either as a
-	 * commmand or a response and is used along with the DLCI to form
-	 * the address. Commands contain the non-initiator address, whereas
-	 * responses contain the initiator address, so the CR value is
-	 * also dependent on the session direction.
-	 */
-	if (type == RFCOMM_FRAME_UA || type == RFCOMM_FRAME_DM)
-		cr = IS_INITIATOR(rs) ? 0 : 1;
-	else
-		cr = IS_INITIATOR(rs) ? 1 : 0;
-
-	hdr = mtod(m, struct rfcomm_cmd_hdr *);
-	hdr->address = RFCOMM_MKADDRESS(cr, dlci);
-	hdr->control = RFCOMM_MKCONTROL(type, 1);   /* PF = 1 */
-	hdr->length = (0x00 << 1) | 0x01;	    /* len = 0x00, EA = 1 */
-
-	fcs = 0xff;
-	fcs = FCS(fcs, hdr->address);
-	fcs = FCS(fcs, hdr->control);
-	fcs = FCS(fcs, hdr->length);
-	fcs = 0xff - fcs;	/* ones complement */
-	hdr->fcs = fcs;
-
-	m->m_pkthdr.len = m->m_len = sizeof(struct rfcomm_cmd_hdr);
-
-	/* empty credit note */
-	credit->rc_dlc = NULL;
-	credit->rc_len = m->m_pkthdr.len;
-	STAILQ_INSERT_TAIL(&rs->rs_credits, credit, rc_next);
-
-	DPRINTFN(5, "dlci %d type %2.2x (%d bytes, fcs=%#2.2x)\n",
-		dlci, type, m->m_pkthdr.len, fcs);
-
-	return l2cap_send(rs->rs_l2cap, m);
-}
-
-/*
- * rfcomm_session_send_uih(rfcomm_session, rfcomm_dlc, credits, mbuf)
- *
- * UIH frame is per DLC data or Multiplexer Control Commands
- * when no DLC is given. Data mbuf is optional (just credits
- * will be sent in that case)
- */
-int
-rfcomm_session_send_uih(struct rfcomm_session *rs, struct rfcomm_dlc *dlc,
-			int credits, struct mbuf *m)
-{
-	struct rfcomm_credit *credit;
-	struct mbuf *m0 = NULL;
-	int err, len;
-	uint8_t fcs, *hdr;
-
-	KKASSERT(rs != NULL);
-
-	len = (m == NULL) ? 0 : m->m_pkthdr.len;
-	KKASSERT(!(credits == 0 && len == 0));
-
-	/*
-	 * Make a credit note for the completion notification
-	 */
-	credit = zalloc(rfcomm_credit_pool);
-	if (credit == NULL)
-		goto nomem;
-
-	credit->rc_len = len;
-	credit->rc_dlc = dlc;
-
-	/*
-	 * Wrap UIH frame information around payload.
-	 *
-	 * [ADDRESS] [CONTROL] [LENGTH] [CREDITS] [...] [FCS]
-	 *
-	 * Address is one octet.
-	 * Control is one octet.
-	 * Length is one or two octets.
-	 * Credits may be one octet.
-	 *
-	 * FCS is one octet and calculated on address and
-	 *	control octets only.
-	 *
-	 * If there are credits to be sent, we will set the PF
-	 * flag and include them in the frame.
-	 */
-	m0 = m_gethdr(M_NOWAIT, MT_DATA);
-	if (m0 == NULL)
-		goto nomem;
-
-	MH_ALIGN(m0, 5);	/* (max 5 header octets) */
-	hdr = mtod(m0, uint8_t *);
-
-	/* CR bit is set according to the initiator of the session */
-	*hdr = RFCOMM_MKADDRESS((IS_INITIATOR(rs) ? 1 : 0),
-				(dlc ? dlc->rd_dlci : 0));
-	fcs = FCS(0xff, *hdr);
-	hdr++;
-
-	/* PF bit is set if credits are being sent */
-	*hdr = RFCOMM_MKCONTROL(RFCOMM_FRAME_UIH, (credits > 0 ? 1 : 0));
-	fcs = FCS(fcs, *hdr);
-	hdr++;
-
-	if (len < (1 << 7)) {
-		*hdr++ = ((len << 1) & 0xfe) | 0x01;	/* 7 bits, EA = 1 */
-	} else {
-		*hdr++ = ((len << 1) & 0xfe);		/* 7 bits, EA = 0 */
-		*hdr++ = ((len >> 7) & 0xff);		/* 8 bits, no EA */
-	}
-
-	if (credits > 0)
-		*hdr++ = (uint8_t)credits;
-
-	m0->m_len = hdr - mtod(m0, uint8_t *);
-
-	/* Append payload */
-	m0->m_next = m;
-	m = NULL;
-
-	m0->m_pkthdr.len = m0->m_len + len;
-
-	/* Append FCS */
-	fcs = 0xff - fcs;	/* ones complement */
-	len = m0->m_pkthdr.len;
-	m_copyback(m0, len, sizeof(fcs), &fcs);
-	if (m0->m_pkthdr.len != len + sizeof(fcs))
-		goto nomem;
-
-	DPRINTFN(10, "dlci %d, pktlen %d (%d data, %d credits), fcs=%#2.2x\n",
-		dlc ? dlc->rd_dlci : 0, m0->m_pkthdr.len, credit->rc_len,
-		credits, fcs);
-
-	/*
-	 * UIH frame ready to go..
-	 */
-	err = l2cap_send(rs->rs_l2cap, m0);
-	if (err)
-		goto fail;
-
-	STAILQ_INSERT_TAIL(&rs->rs_credits, credit, rc_next);
-	return 0;
-
-nomem:
-	err = ENOMEM;
-
-	if (m0 != NULL)
-		m_freem(m0);
-
-	if (m != NULL)
-		m_freem(m);
-
-fail:
-	if (credit != NULL)
-		zfree(rfcomm_credit_pool, credit);
-
-	return err;
-}
-
-/*
- * send Multiplexer Control Command (or Response) on session
- */
-int
-rfcomm_session_send_mcc(struct rfcomm_session *rs, int cr,
-			uint8_t type, void *data, int len)
-{
-	struct mbuf *m;
-	uint8_t *hdr;
-	int hlen;
-
-	m = m_gethdr(M_NOWAIT, MT_DATA);
-	if (m == NULL)
-		return ENOMEM;
-
-	hdr = mtod(m, uint8_t *);
-
-	/*
-	 * Technically the type field can extend past one octet, but none
-	 * currently defined will do that.
-	 */
-	*hdr++ = RFCOMM_MKMCC_TYPE(cr, type);
-
-	/*
-	 * In the frame, the max length size is 2 octets (15 bits) whereas
-	 * no max length size is specified for MCC commands. We must allow
-	 * for 3 octets since for MCC frames we use 7 bits + EA in each.
-	 *
-	 * Only test data can possibly be that big.
-	 *
-	 * XXX Should we check this against the MTU?
-	 */
-	if (len < (1 << 7)) {
-		*hdr++ = ((len << 1) & 0xfe) | 0x01;	/* 7 bits, EA = 1 */
-	} else if (len < (1 << 14)) {
-		*hdr++ = ((len << 1) & 0xfe);		/* 7 bits, EA = 0 */
-		*hdr++ = ((len >> 6) & 0xfe) | 0x01;	/* 7 bits, EA = 1 */
-	} else if (len < (1 << 15)) {
-		*hdr++ = ((len << 1) & 0xfe);		/* 7 bits, EA = 0 */
-		*hdr++ = ((len >> 6) & 0xfe);		/* 7 bits, EA = 0 */
-		*hdr++ = ((len >> 13) & 0x02) | 0x01;	/* 1 bit,  EA = 1 */
-	} else {
-		DPRINTF("incredible length! (%d)\n", len);
-		m_freem(m);
-		return EMSGSIZE;
-	}
-
-	/*
-	 * add command data (to same mbuf if possible)
-	 */
-	hlen = hdr - mtod(m, uint8_t *);
-
-	if (len > 0) {
-		m->m_pkthdr.len = m->m_len = MHLEN;
-		m_copyback(m, hlen, len, data);
-		if (m->m_pkthdr.len != max(MHLEN, hlen + len)) {
-			m_freem(m);
-			return ENOMEM;
-		}
-	}
-
-	m->m_pkthdr.len = hlen + len;
-	m->m_len = min(MHLEN, m->m_pkthdr.len);
-
-	DPRINTFN(5, "%s type %2.2x len %d\n",
-		(cr ? "command" : "response"), type, m->m_pkthdr.len);
-
-	return rfcomm_session_send_uih(rs, NULL, 0, m);
-}
diff --git a/sys/netbt/rfcomm_socket.c b/sys/netbt/rfcomm_socket.c
deleted file mode 100644
index aa5399d9a2..0000000000
--- a/sys/netbt/rfcomm_socket.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/* $OpenBSD: src/sys/netbt/rfcomm_socket.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: rfcomm_socket.c,v 1.8 2007/10/15 18:04:34 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
-
-/* load symbolic names */
-#ifdef BLUETOOTH_DEBUG
-#define PRUREQUESTS
-#define PRCOREQUESTS
-#endif
-
-#include <sys/param.h>
-#include <sys/domain.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>	/* for M_NOWAIT */
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/protosw.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/systm.h>
-
-#include <sys/msgport2.h>
-
-#include <vm/vm_zone.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>		/* XXX for EPASSTHROUGH */
-#include <netbt/rfcomm.h>
-
-/****************************************************************************
- *
- *	RFCOMM SOCK_STREAM Sockets - serial line emulation
- *
- */
-
-static void rfcomm_connecting(void *);
-static void rfcomm_connected(void *);
-static void rfcomm_disconnected(void *, int);
-static void *rfcomm_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
-static void rfcomm_complete(void *, int);
-static void rfcomm_linkmode(void *, int);
-static void rfcomm_input(void *, struct mbuf *);
-
-static const struct btproto rfcomm_proto = {
-	rfcomm_connecting,
-	rfcomm_connected,
-	rfcomm_disconnected,
-	rfcomm_newconn,
-	rfcomm_complete,
-	rfcomm_linkmode,
-	rfcomm_input,
-};
-
-/* sysctl variables */
-int rfcomm_sendspace = 4096;
-int rfcomm_recvspace = 4096;
-
-/*
- * rfcomm_ctloutput(request, socket, level, optname, opt)
- *
- */
-void
-rfcomm_ctloutput(netmsg_t msg)
-{
-	struct socket *so = msg->ctloutput.base.nm_so;
-	struct sockopt *sopt = msg->ctloutput.nm_sopt;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
-	struct mbuf *m;
-	int error = 0;
-
-#ifdef notyet			/* XXX */
-	DPRINTFN(2, "%s\n", prcorequests[sopt->sopt_dir]);
-#endif
-
-	if (pcb == NULL) {
-		error = EINVAL;
-		goto out;
-	}
-
-	if (sopt->sopt_level != BTPROTO_RFCOMM) {
-		error = ENOPROTOOPT;
-		goto out;
-	}
-
-	switch(sopt->sopt_dir) {
-	case PRCO_GETOPT:
-		m = m_get(M_WAITOK, MT_DATA);
-		crit_enter();
-		m->m_len = rfcomm_getopt(pcb, sopt->sopt_name, mtod(m, void *));
-		crit_exit();		
-		if (m->m_len == 0) {
-			m_freem(m);
-			m = NULL;
-			error = ENOPROTOOPT;
-		}
-		soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
-		break;
-
-	case PRCO_SETOPT:
-		error = rfcomm_setopt2(pcb, sopt->sopt_name, so, sopt);
-
-		break;
-
-	default:
-		error = ENOPROTOOPT;
-		break;
-	}
-out:
-	lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
-}
-
-/**********************************************************************
- *
- * RFCOMM callbacks
- */
-
-static void
-rfcomm_connecting(void *arg)
-{
-	/* struct socket *so = arg; */
-
-	KKASSERT(arg != NULL);
-	DPRINTF("Connecting\n");
-}
-
-static void
-rfcomm_connected(void *arg)
-{
-	struct socket *so = arg;
-
-	KKASSERT(so != NULL);
-	DPRINTF("Connected\n");
-	soisconnected(so);
-}
-
-static void
-rfcomm_disconnected(void *arg, int err)
-{
-	struct socket *so = arg;
-
-	KKASSERT(so != NULL);
-	DPRINTF("Disconnected\n");
-
-	so->so_error = err;
-	soisdisconnected(so);
-}
-
-static void *
-rfcomm_newconn(void *arg, struct sockaddr_bt *laddr,
-    struct sockaddr_bt *raddr)
-{
-	struct socket *so = arg;
-
-	DPRINTF("New Connection\n");
-	so = sonewconn(so, 0);
-	if (so == NULL)
-		return NULL;
-
-	soisconnecting(so);
-
-	return so->so_pcb;
-}
-
-/*
- * rfcomm_complete(rfcomm_dlc, length)
- *
- * length bytes are sent and may be removed from socket buffer
- */
-static void
-rfcomm_complete(void *arg, int length)
-{
-	struct socket *so = arg;
-
-	sbdrop(&so->so_snd.sb, length);
-	sowwakeup(so);
-}
-
-/*
- * rfcomm_linkmode(rfcomm_dlc, new)
- *
- * link mode change notification.
- */
-static void
-rfcomm_linkmode(void *arg, int new)
-{
-	struct socket *so = arg;
-	int mode;
-
-	DPRINTF("auth %s, encrypt %s, secure %s\n",
-		(new & RFCOMM_LM_AUTH ? "on" : "off"),
-		(new & RFCOMM_LM_ENCRYPT ? "on" : "off"),
-		(new & RFCOMM_LM_SECURE ? "on" : "off"));
-
-	(void)rfcomm_getopt(so->so_pcb, SO_RFCOMM_LM, &mode);
-	if (((mode & RFCOMM_LM_AUTH) && !(new & RFCOMM_LM_AUTH))
-	    || ((mode & RFCOMM_LM_ENCRYPT) && !(new & RFCOMM_LM_ENCRYPT))
-	    || ((mode & RFCOMM_LM_SECURE) && !(new & RFCOMM_LM_SECURE)))
-		rfcomm_disconnect(so->so_pcb, 0);
-}
-
-/*
- * rfcomm_input(rfcomm_dlc, mbuf)
- */
-static void
-rfcomm_input(void *arg, struct mbuf *m)
-{
-	struct socket *so = arg;
-
-	KKASSERT(so != NULL);
-
-	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
-		kprintf("%s: %d bytes dropped (socket buffer full)\n",
-			__func__, m->m_pkthdr.len);
-		m_freem(m);
-		return;
-	}
-
-	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
-
-	sbappendstream(&so->so_rcv.sb, m);
-	sorwakeup(so);
-}
-
-/*
- * Implementation of usrreqs.
- */
-static void
-rfcomm_sdetach(netmsg_t msg)
-{
-	struct socket *so = msg->detach.base.nm_so;
-	int error;
-
-	error = rfcomm_detach((struct rfcomm_dlc **)&so->so_pcb);
-	lwkt_replymsg(&msg->detach.base.lmsg, error);
-}
-
-/*
- * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
- *	 will sofree() it when we return.
- */
-static void
-rfcomm_sabort(netmsg_t msg)
-{
-	struct socket *so = msg->abort.base.nm_so;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
-
-	rfcomm_disconnect(pcb, 0);
-	soisdisconnected(so);
-	rfcomm_sdetach(msg);
-	/* msg invalid now */
-}
-
-static void
-rfcomm_sdisconnect(netmsg_t msg)
-{
-	struct socket *so = msg->abort.base.nm_so;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
-	int error;
-
-	soisdisconnecting(so);
-	error = rfcomm_disconnect(pcb, so->so_linger);
-	lwkt_replymsg(&msg->disconnect.base.lmsg, error);
-}
-
-static void
-rfcomm_scontrol(netmsg_t msg)
-{
-	lwkt_replymsg(&msg->control.base.lmsg, EPASSTHROUGH);
-}
-
-static void
-rfcomm_sattach(netmsg_t msg)
-{
-	struct socket *so = msg->attach.base.nm_so;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
-	int error;
-
-	if (pcb != NULL) {
-		error = EINVAL;
-		goto out;
-	}
-
-	/*
-	 * Since we have nothing to add, we attach the DLC
-	 * structure directly to our PCB pointer.
-	 */
-	error = soreserve(so, rfcomm_sendspace, rfcomm_recvspace, NULL);
-	if (error)
-		goto out;
-
-	error = rfcomm_attach((struct rfcomm_dlc **)&so->so_pcb,
-			      &rfcomm_proto, so);
-	if (error)
-		goto out;
-
-	error = rfcomm_rcvd(so->so_pcb, sbspace(&so->so_rcv));
-	if (error)
-		rfcomm_detach((struct rfcomm_dlc **)&so->so_pcb);
-out:
-	lwkt_replymsg(&msg->attach.base.lmsg, error);
-}
-
-static void
-rfcomm_sbind(netmsg_t msg)
-{
-	struct socket *so = msg->bind.base.nm_so;
-	struct sockaddr *nam = msg->bind.nm_nam;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
-	struct sockaddr_bt *sa;
-	int error;
-
-	KKASSERT(nam != NULL);
-	sa = (struct sockaddr_bt *)nam;
-
-	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
-		error = EINVAL;
-	} else if (sa->bt_family != AF_BLUETOOTH) {
-		error = EAFNOSUPPORT;
-	} else {
-		error = rfcomm_bind(pcb, sa);
-	}
-	lwkt_replymsg(&msg->bind.base.lmsg, error);
-}
-
-static void
-rfcomm_sconnect(netmsg_t msg)
-{
-	struct socket *so = msg->connect.base.nm_so;
-	struct sockaddr *nam = msg->connect.nm_nam;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
-	struct sockaddr_bt *sa;
-	int error;
-
-	KKASSERT(nam != NULL);
-	sa = (struct sockaddr_bt *)nam;
-
-	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
-		error = EINVAL;
-	} else if (sa->bt_family != AF_BLUETOOTH) {
-		error = EAFNOSUPPORT;
-	} else {
-		soisconnecting(so);
-		error = rfcomm_connect(pcb, sa);
-	}
-	lwkt_replymsg(&msg->connect.base.lmsg, error);
-}
-
-static void
-rfcomm_speeraddr(netmsg_t msg)
-{
-	struct socket *so = msg->peeraddr.base.nm_so;
-	struct sockaddr **nam = msg->peeraddr.nm_nam;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
-	struct sockaddr_bt *sa, ssa;
-	int error;
-
-	sa = &ssa;
-	bzero(sa, sizeof *sa);
-	sa->bt_len = sizeof(struct sockaddr_bt);
-	sa->bt_family = AF_BLUETOOTH;
-	error = rfcomm_peeraddr(pcb, sa);
-	*nam = dup_sockaddr((struct sockaddr *)sa);
-
-	lwkt_replymsg(&msg->peeraddr.base.lmsg, error);
-}
-
-static void
-rfcomm_ssockaddr(netmsg_t msg)
-{
-	struct socket *so = msg->sockaddr.base.nm_so;
-	struct sockaddr **nam = msg->sockaddr.nm_nam;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
-	struct sockaddr_bt *sa, ssa;
-	int error;
-
-	sa = &ssa;
-	bzero(sa, sizeof *sa);
-	sa->bt_len = sizeof(struct sockaddr_bt);
-	sa->bt_family = AF_BLUETOOTH;
-	error = rfcomm_sockaddr(pcb, sa);
-	*nam = dup_sockaddr((struct sockaddr *)sa);
-
-	lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
-}
-
-static void
-rfcomm_sshutdown(netmsg_t msg)
-{
-	struct socket *so = msg->shutdown.base.nm_so;
-
-	socantsendmore(so);
-	lwkt_replymsg(&msg->shutdown.base.lmsg, 0);
-}
-
-static void
-rfcomm_ssend(netmsg_t msg)
-{
-	struct socket *so = msg->send.base.nm_so;
-	struct mbuf *m = msg->send.nm_m;
-	struct mbuf *control = msg->send.nm_control;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
-	struct mbuf *m0;
-	int error;
-
-	KKASSERT(m != NULL);
-
-	/* no use for that */
-	if (control) {
-		m_freem(control);
-		control = NULL;
-	}
-
-	m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
-	if (m0) {
-		sbappendstream(&so->so_snd.sb, m);
-		error = rfcomm_send(pcb, m0);
-	} else {
-		error = ENOMEM;
-	}
-	lwkt_replymsg(&msg->send.base.lmsg, error);
-}
-
-static void
-rfcomm_saccept(netmsg_t msg)
-{
-	struct socket *so = msg->accept.base.nm_so;
-	struct sockaddr **nam = msg->accept.nm_nam;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
-	struct sockaddr_bt *sa, ssa;
-	int error;
-
-	sa = &ssa;
-	bzero(sa, sizeof *sa);
-	sa->bt_len = sizeof(struct sockaddr_bt);
-	sa->bt_family = AF_BLUETOOTH;
-	error = rfcomm_peeraddr(pcb, sa);
-	*nam = dup_sockaddr((struct sockaddr *)sa);
-
-	lwkt_replymsg(&msg->accept.base.lmsg, error);
-}
-
-static void
-rfcomm_slisten(netmsg_t msg)
-{
-	struct socket *so = msg->listen.base.nm_so;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *)so->so_pcb;
-	int error;
-
-	error = rfcomm_listen(pcb);
-	lwkt_replymsg(&msg->listen.base.lmsg, error);
-}
-
-static void
-rfcomm_srcvd(netmsg_t msg)
-{
-	struct socket *so = msg->rcvd.base.nm_so;
-	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb; 
-	int error;
-
-	error = rfcomm_rcvd(pcb, sbspace(&so->so_rcv));
-	lwkt_replymsg(&msg->rcvd.base.lmsg, error);
-}
-
-struct pr_usrreqs rfcomm_usrreqs = {
-        .pru_abort = rfcomm_sabort,
-        .pru_accept = rfcomm_saccept,
-        .pru_attach = rfcomm_sattach,
-        .pru_bind = rfcomm_sbind,
-        .pru_connect = rfcomm_sconnect,
-        .pru_connect2 = pr_generic_notsupp,
-        .pru_control = rfcomm_scontrol,
-        .pru_detach = rfcomm_sdetach,
-        .pru_disconnect = rfcomm_sdisconnect,
-        .pru_listen = rfcomm_slisten,
-        .pru_peeraddr = rfcomm_speeraddr,
-        .pru_rcvd = rfcomm_srcvd,
-        .pru_rcvoob = pr_generic_notsupp,
-        .pru_send = rfcomm_ssend,
-        .pru_sense = pru_sense_null,
-        .pru_shutdown = rfcomm_sshutdown,
-        .pru_sockaddr = rfcomm_ssockaddr,
-        .pru_sosend = sosend,
-        .pru_soreceive = soreceive
-};
diff --git a/sys/netbt/rfcomm_upper.c b/sys/netbt/rfcomm_upper.c
deleted file mode 100644
index 387aebf73a..0000000000
--- a/sys/netbt/rfcomm_upper.c
+++ /dev/null
@@ -1,567 +0,0 @@
-/* $OpenBSD: src/sys/netbt/rfcomm_upper.c,v 1.4 2008/02/24 21:34:48 uwe Exp $ */
-/* $NetBSD: rfcomm_upper.c,v 1.10 2007/11/20 20:25:57 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/systm.h>
-#include <sys/socketvar.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/l2cap.h>
-#include <netbt/rfcomm.h>
-
-/****************************************************************************
- *
- *	RFCOMM DLC - Upper Protocol API
- *
- * Currently the only 'Port Emulation Entity' is the RFCOMM socket code
- * but it is should be possible to provide a pseudo-device for a direct
- * tty interface.
- */
-
-/*
- * rfcomm_attach(handle, proto, upper)
- *
- * attach a new RFCOMM DLC to handle, populate with reasonable defaults
- */
-int
-rfcomm_attach(struct rfcomm_dlc **handle,
-		const struct btproto *proto, void *upper)
-{
-	struct rfcomm_dlc *dlc;
-
-	KKASSERT(handle != NULL);
-	KKASSERT(proto != NULL);
-	KKASSERT(upper != NULL);
-
-	dlc = kmalloc(sizeof(*dlc), M_BLUETOOTH, M_NOWAIT | M_ZERO);
-	if (dlc == NULL)
-		return ENOMEM;
-
-	dlc->rd_state = RFCOMM_DLC_CLOSED;
-	dlc->rd_mtu = rfcomm_mtu_default;
-
-	dlc->rd_proto = proto;
-	dlc->rd_upper = upper;
-
-	dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt);
-	dlc->rd_laddr.bt_family = AF_BLUETOOTH;
-	dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
-
-	dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt);
-	dlc->rd_raddr.bt_family = AF_BLUETOOTH;
-	dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
-
-	dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV;
-
-	callout_init(&dlc->rd_timeout);
-
-	*handle = dlc;
-	return 0;
-}
-
-/*
- * rfcomm_bind(dlc, sockaddr)
- *
- * bind DLC to local address
- */
-int
-rfcomm_bind(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
-{
-
-	memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
-	return 0;
-}
-
-/*
- * rfcomm_sockaddr(dlc, sockaddr)
- *
- * return local address
- */
-int
-rfcomm_sockaddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
-{
-
-	memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
-	return 0;
-}
-
-/*
- * rfcomm_connect(dlc, sockaddr)
- *
- * Initiate connection of RFCOMM DLC to remote address.
- */
-int
-rfcomm_connect(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
-{
-	struct rfcomm_session *rs;
-	int err = 0;
-
-	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
-		return EISCONN;
-
-	memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
-
-	if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN
-	    || dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX
-	    || bdaddr_any(&dlc->rd_raddr.bt_bdaddr))
-		return EDESTADDRREQ;
-
-	if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY)
-		dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
-	else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM
-	    && (dlc->rd_raddr.bt_psm < 0x1001
-	    || L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm)))
-		return EINVAL;
-
-	/*
-	 * We are allowed only one RFCOMM session between any 2 Bluetooth
-	 * devices, so see if there is a session already otherwise create
-	 * one and set it connecting.
-	 */
-	rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr);
-	if (rs == NULL) {
-		rs = rfcomm_session_alloc(&rfcomm_session_active,
-						&dlc->rd_laddr);
-		if (rs == NULL)
-			return ENOMEM;
-
-		rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
-		rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
-
-		err = l2cap_connect(rs->rs_l2cap, &dlc->rd_raddr);
-		if (err) {
-			rfcomm_session_free(rs);
-			return err;
-		}
-
-		/*
-		 * This session will start up automatically when its
-		 * L2CAP channel is connected.
-		 */
-	}
-
-	/* construct DLC */
-	dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel);
-	if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
-		return EBUSY;
-
-	l2cap_sockaddr(rs->rs_l2cap, &dlc->rd_laddr);
-
-	/*
-	 * attach the DLC to the session and start it off
-	 */
-	dlc->rd_session = rs;
-	dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
-	LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
-
-	if (rs->rs_state == RFCOMM_SESSION_OPEN)
-		err = rfcomm_dlc_connect(dlc);
-
-	return err;
-}
-
-/*
- * rfcomm_peeraddr(dlc, sockaddr)
- *
- * return remote address
- */
-int
-rfcomm_peeraddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
-{
-
-	memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
-	return 0;
-}
-
-/*
- * rfcomm_disconnect(dlc, linger)
- *
- * disconnect RFCOMM DLC
- */
-int
-rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
-{
-	struct rfcomm_session *rs = dlc->rd_session;
-	int err = 0;
-
-	KKASSERT(dlc != NULL);
-
-	switch (dlc->rd_state) {
-	case RFCOMM_DLC_CLOSED:
-	case RFCOMM_DLC_LISTEN:
-		return EINVAL;
-
-	case RFCOMM_DLC_WAIT_SEND_UA:
-		err = rfcomm_session_send_frame(rs,
-				RFCOMM_FRAME_DM, dlc->rd_dlci);
-
-		/* fall through */
-	case RFCOMM_DLC_WAIT_SESSION:
-	case RFCOMM_DLC_WAIT_CONNECT:
-	case RFCOMM_DLC_WAIT_SEND_SABM:
-		rfcomm_dlc_close(dlc, 0);
-		break;
-
-	case RFCOMM_DLC_OPEN:
-		if (dlc->rd_txbuf != NULL && linger != 0) {
-			dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
-			break;
-		}
-
-		/* else fall through */
-	case RFCOMM_DLC_WAIT_RECV_UA:
-		dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
-		err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
-							dlc->rd_dlci);
-		callout_reset(&dlc->rd_timeout, rfcomm_ack_timeout * hz,
-		    rfcomm_dlc_timeout, dlc);
-		break;
-
-	case RFCOMM_DLC_WAIT_DISCONNECT:
-		err = EALREADY;
-		break;
-
-	default:
-		UNKNOWN(dlc->rd_state);
-		break;
-	}
-
-	return err;
-}
-
-/*
- * rfcomm_detach(handle)
- *
- * detach RFCOMM DLC from handle
- */
-int
-rfcomm_detach(struct rfcomm_dlc **handle)
-{
-	struct rfcomm_dlc *dlc = *handle;
-
-	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
-		rfcomm_dlc_close(dlc, 0);
-
-	if (dlc->rd_txbuf != NULL) {
-		m_freem(dlc->rd_txbuf);
-		dlc->rd_txbuf = NULL;
-	}
-
-	dlc->rd_upper = NULL;
-	*handle = NULL;
-
-	/*
-	 * If callout is invoking we can't free the DLC so
-	 * mark it and let the callout release it.
-	 */
-	if (callout_active(&dlc->rd_timeout))
-		dlc->rd_flags |= RFCOMM_DLC_DETACH;
-	else
-		kfree(dlc, M_BLUETOOTH);
-
-	return 0;
-}
-
-/*
- * rfcomm_listen(dlc)
- *
- * This DLC is a listener. We look for an existing listening session
- * with a matching address to attach to or else create a new one on
- * the listeners list. If the ANY channel is given, allocate the first
- * available for the session.
- */
-int
-rfcomm_listen(struct rfcomm_dlc *dlc)
-{
-	struct rfcomm_session *rs;
-	struct rfcomm_dlc *used;
-	struct sockaddr_bt addr;
-	int err, channel;
-
-	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
-		return EISCONN;
-
-	if (dlc->rd_laddr.bt_channel != RFCOMM_CHANNEL_ANY
-	    && (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
-	    || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX))
-		return EADDRNOTAVAIL;
-
-	if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
-		dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
-	else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
-	    && (dlc->rd_laddr.bt_psm < 0x1001
-	    || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
-		return EADDRNOTAVAIL;
-
-	LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
-		l2cap_sockaddr(rs->rs_l2cap, &addr);
-
-		if (addr.bt_psm != dlc->rd_laddr.bt_psm)
-			continue;
-
-		if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
-			break;
-	}
-
-	if (rs == NULL) {
-		rs = rfcomm_session_alloc(&rfcomm_session_listen,
-						&dlc->rd_laddr);
-		if (rs == NULL)
-			return ENOMEM;
-
-		rs->rs_state = RFCOMM_SESSION_LISTEN;
-
-		err = l2cap_listen(rs->rs_l2cap);
-		if (err) {
-			rfcomm_session_free(rs);
-			return err;
-		}
-	}
-
-	if (dlc->rd_laddr.bt_channel == RFCOMM_CHANNEL_ANY) {
-		channel = RFCOMM_CHANNEL_MIN;
-		used = LIST_FIRST(&rs->rs_dlcs);
-
-		while (used != NULL) {
-			if (used->rd_laddr.bt_channel == channel) {
-				if (channel++ == RFCOMM_CHANNEL_MAX)
-					return EADDRNOTAVAIL;
-
-				used = LIST_FIRST(&rs->rs_dlcs);
-			} else {
-				used = LIST_NEXT(used, rd_next);
-			}
-		}
-
-		dlc->rd_laddr.bt_channel = channel;
-	}
-
-	dlc->rd_session = rs;
-	dlc->rd_state = RFCOMM_DLC_LISTEN;
-	LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
-
-	return 0;
-}
-
-/*
- * rfcomm_send(dlc, mbuf)
- *
- * Output data on DLC. This is streamed data, so we add it
- * to our buffer and start the DLC, which will assemble
- * packets and send them if it can.
- */
-int
-rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m)
-{
-
-	if (dlc->rd_txbuf != NULL) {
-		dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
-		m_cat(dlc->rd_txbuf, m);
-	} else {
-		dlc->rd_txbuf = m;
-	}
-
-	if (dlc->rd_state == RFCOMM_DLC_OPEN)
-		rfcomm_dlc_start(dlc);
-
-	return 0;
-}
-
-/*
- * rfcomm_rcvd(dlc, space)
- *
- * Indicate space now available in receive buffer
- *
- * This should be used to give an initial value of the receive buffer
- * size when the DLC is attached and anytime data is cleared from the
- * buffer after that.
- */
-int
-rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
-{
-
-	KKASSERT(dlc != NULL);
-
-	dlc->rd_rxsize = space;
-
-	/*
-	 * if we are using credit based flow control, we may
-	 * want to send some credits..
-	 */
-	if (dlc->rd_state == RFCOMM_DLC_OPEN
-	    && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
-		rfcomm_dlc_start(dlc);
-
-	return 0;
-}
-
-/*
- * rfcomm_setopt(dlc, option, addr)
- *
- * set DLC options
- */
-int
-rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
-{
-	int mode, err = 0;
-	uint16_t mtu;
-
-	switch (opt) {
-	case SO_RFCOMM_MTU:
-		mtu = *(uint16_t *)addr;
-		if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
-			err = EINVAL;
-		else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
-			dlc->rd_mtu = mtu;
-		else
-			err = EBUSY;
-
-		break;
-
-	case SO_RFCOMM_LM:
-		mode = *(int *)addr;
-		mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
-
-		if (mode & RFCOMM_LM_SECURE)
-			mode |= RFCOMM_LM_ENCRYPT;
-
-		if (mode & RFCOMM_LM_ENCRYPT)
-			mode |= RFCOMM_LM_AUTH;
-
-		dlc->rd_mode = mode;
-
-		if (dlc->rd_state == RFCOMM_DLC_OPEN)
-			err = rfcomm_dlc_setmode(dlc);
-
-		break;
-
-	default:
-		err = ENOPROTOOPT;
-		break;
-	}
-	return err;
-}
-
-
-int
-rfcomm_setopt2(struct rfcomm_dlc *dlc, int opt, struct socket *so,
-    struct sockopt *sopt)
-{
-	int mode, err = 0;
-	uint16_t mtu;
-
-	switch (opt) {
-	case SO_RFCOMM_MTU:
-		err = soopt_to_kbuf(sopt, &mtu, sizeof(uint16_t),
-		    sizeof(uint16_t)); 
-		if (err) break;
-
-		if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
-			err = EINVAL;
-		else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
-			dlc->rd_mtu = mtu;
-		else
-			err = EBUSY;
-
-		break;
-
-	case SO_RFCOMM_LM:
-		err = soopt_to_kbuf(sopt, &mode, sizeof(int), sizeof(int)); 
-		if (err) break;
-
-		mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
-
-		if (mode & RFCOMM_LM_SECURE)
-			mode |= RFCOMM_LM_ENCRYPT;
-
-		if (mode & RFCOMM_LM_ENCRYPT)
-			mode |= RFCOMM_LM_AUTH;
-
-		dlc->rd_mode = mode;
-
-		if (dlc->rd_state == RFCOMM_DLC_OPEN)
-			err = rfcomm_dlc_setmode(dlc);
-
-		break;
-
-	default:
-		err = ENOPROTOOPT;
-		break;
-	}
-	return err;
-}
-
-/*
- * rfcomm_getopt(dlc, option, addr)
- *
- * get DLC options
- */
-int
-rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
-{
-	struct rfcomm_fc_info *fc;
-
-	switch (opt) {
-	case SO_RFCOMM_MTU:
-		*(uint16_t *)addr = dlc->rd_mtu;
-		return sizeof(uint16_t);
-
-	case SO_RFCOMM_FC_INFO:
-		fc = addr;
-		memset(fc, 0, sizeof(*fc));
-		fc->lmodem = dlc->rd_lmodem;
-		fc->rmodem = dlc->rd_rmodem;
-		fc->tx_cred = max(dlc->rd_txcred, 0xff);
-		fc->rx_cred = max(dlc->rd_rxcred, 0xff);
-		if (dlc->rd_session
-		    && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
-			fc->cfc = 1;
-
-		return sizeof(*fc);
-
-	case SO_RFCOMM_LM:
-		*(int *)addr = dlc->rd_mode;
-		return sizeof(int);
-
-	default:
-		break;
-	}
-
-	return 0;
-}
diff --git a/sys/netbt/sco.h b/sys/netbt/sco.h
deleted file mode 100644
index 1821dc9322..0000000000
--- a/sys/netbt/sco.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* $DragonFly: src/sys/netbt/sco.h,v 1.2 2008/03/18 13:41:42 hasso Exp $ */
-/* $OpenBSD: sco.h,v 1.2 2007/06/01 02:46:12 uwe Exp $ */
-/* $NetBSD: sco.h,v 1.2 2006/07/26 10:20:56 tron Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
-
-#ifndef _NETBT_SCO_H_
-#define _NETBT_SCO_H_
-
-#define SO_SCO_MTU		1
-#define SO_SCO_HANDLE		2
-
-#ifdef _KERNEL
-/*
- * SCO protocol control block
- */
-struct sco_pcb {
-	struct hci_link		*sp_link;	/* SCO link */
-	unsigned int		 sp_flags;	/* flags */
-	bdaddr_t		 sp_laddr;	/* local address */
-	bdaddr_t		 sp_raddr;	/* remote address */
-	unsigned int		 sp_mtu;	/* link MTU */
-	int			 sp_pending;	/* number of packets pending */
-
-	const struct btproto	*sp_proto;	/* upper layer protocol */
-	void			*sp_upper;	/* upper layer argument */
-
-	LIST_ENTRY(sco_pcb)	 sp_next;
-};
-
-LIST_HEAD(sco_pcb_list, sco_pcb);
-extern struct sco_pcb_list sco_pcb;
-
-/* sp_flags */
-#define SP_LISTENING		(1<<0)		/* is listening pcb */
-
-/* sco_socket.c */
-struct socket;
-union netmsg;
-
-extern struct pr_usrreqs sco_usrreqs;
-extern int sco_sendspace;
-extern int sco_recvspace;
-int sco_usrreq(struct socket *, int, struct mbuf *,
-		struct mbuf *, struct mbuf *);
-void sco_ctloutput(union netmsg *);
-
-/* sco_upper.c */
-int sco_attach(struct sco_pcb **, const struct btproto *, void *);
-int sco_bind(struct sco_pcb *, struct sockaddr_bt *);
-int sco_sockaddr(struct sco_pcb *, struct sockaddr_bt *);
-int sco_connect(struct sco_pcb *, struct sockaddr_bt *);
-int sco_peeraddr(struct sco_pcb *, struct sockaddr_bt *);
-int sco_disconnect(struct sco_pcb *, int);
-int sco_detach(struct sco_pcb **);
-int sco_listen(struct sco_pcb *);
-int sco_send(struct sco_pcb *, struct mbuf *);
-int sco_setopt(struct sco_pcb *, int, void *);
-int sco_getopt(struct sco_pcb *, int, void *);
-
-#endif	/* _KERNEL */
-
-#endif	/* _NETBT_SCO_H_ */
diff --git a/sys/netbt/sco_socket.c b/sys/netbt/sco_socket.c
deleted file mode 100644
index cf60dee98b..0000000000
--- a/sys/netbt/sco_socket.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- *
- * $OpenBSD: sco_socket.c,v 1.1 2007/06/01 02:46:12 uwe Exp $
- * $NetBSD: sco_socket.c,v 1.9 2007/04/21 06:15:23 plunky Exp $
- */
-
-/* load symbolic names */
-#ifdef BLUETOOTH_DEBUG
-#define PRUREQUESTS
-#define PRCOREQUESTS
-#endif
-
-#include <sys/param.h>
-#include <sys/domain.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>	/* for M_NOWAIT */
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/protosw.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-
-#include <sys/msgport2.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/sco.h>
-
-/*******************************************************************************
- *
- * SCO SOCK_SEQPACKET sockets - low latency audio data
- */
-
-static void sco_connecting(void *);
-static void sco_connected(void *);
-static void sco_disconnected(void *, int);
-static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
-static void sco_complete(void *, int);
-static void sco_linkmode(void *, int);
-static void sco_input(void *, struct mbuf *);
-
-static const struct btproto sco_proto = {
-	sco_connecting,
-	sco_connected,
-	sco_disconnected,
-	sco_newconn,
-	sco_complete,
-	sco_linkmode,
-	sco_input,
-};
-
-int sco_sendspace = 4096;
-int sco_recvspace = 4096;
-
-/*
- * get/set socket options
- */
-void
-sco_ctloutput(netmsg_t msg)
-{
-	struct socket *so = msg->ctloutput.base.nm_so;
-	struct sockopt *sopt = msg->ctloutput.nm_sopt;
-	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	struct mbuf *m;
-	int err = 0;
-
-#ifdef notyet			/* XXX */
-	DPRINTFN(2, "req %s\n", prcorequests[req]);
-#endif
-
-	if (pcb == NULL) {
-		err = EINVAL;
-		goto out;
-	}
-
-	if (sopt->sopt_level != BTPROTO_SCO) {
-		err = ENOPROTOOPT;
-		goto out;
-	}
-
-	switch(sopt->sopt_dir) {
-	case PRCO_GETOPT:
-		m = m_get(M_WAITOK, MT_DATA);
-		m->m_len = sco_getopt(pcb, sopt->sopt_name, mtod(m, uint8_t *));
-		if (m->m_len == 0) {
-			m_freem(m);
-			m = NULL;
-			err = ENOPROTOOPT;
-		}
-		/* *opt = m; */
-		/* XXX There are possible memory leaks (Griffin) */
-		soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
-		break;
-
-	case PRCO_SETOPT:
-		m = m_get(M_WAITOK, MT_DATA);
-		KKASSERT(m != NULL);
-		err = soopt_to_kbuf(sopt, mtod(m,void*), m->m_len, m->m_len); 
-
-		if (m->m_len == 0) {
-			m_freem(m);
-			m = NULL;
-			err = EIO;
-		}
-
-		err = sco_setopt(pcb, sopt->sopt_name, mtod(m, uint8_t *));
-		m_freem(m);
-		break;
-
-	default:
-		err = ENOPROTOOPT;
-		break;
-	}
-out:
-	lwkt_replymsg(&msg->ctloutput.base.lmsg, err);
-}
-
-/*****************************************************************************
- *
- *	SCO Protocol socket callbacks
- *
- */
-static void
-sco_connecting(void *arg)
-{
-	struct socket *so = arg;
-
-	DPRINTF("Connecting\n");
-	soisconnecting(so);
-}
-
-static void
-sco_connected(void *arg)
-{
-	struct socket *so = arg;
-
-	DPRINTF("Connected\n");
-	soisconnected(so);
-}
-
-static void
-sco_disconnected(void *arg, int err)
-{
-	struct socket *so = arg;
-
-	DPRINTF("Disconnected (%d)\n", err);
-
-	so->so_error = err;
-	soisdisconnected(so);
-}
-
-static void *
-sco_newconn(void *arg, struct sockaddr_bt *laddr,
-    struct sockaddr_bt *raddr)
-{
-	struct socket *so = arg;
-
-	DPRINTF("New Connection\n");
-	so = sonewconn(so, 0);
-	if (so == NULL)
-		return NULL;
-
-	soisconnecting(so);
-	return so->so_pcb;
-}
-
-static void
-sco_complete(void *arg, int num)
-{
-	struct socket *so = arg;
-
-	while (num-- > 0)
-		sbdroprecord(&so->so_snd.sb);
-
-	sowwakeup(so);
-}
-
-static void
-sco_linkmode(void *arg, int mode)
-{
-}
-
-static void
-sco_input(void *arg, struct mbuf *m)
-{
-	struct socket *so = arg;
-
-	/*
-	 * since this data is time sensitive, if the buffer
-	 * is full we just dump data until the latest one
-	 * will fit.
-	 */
-
-	while (m->m_pkthdr.len > sbspace(&so->so_rcv))
-		sbdroprecord(&so->so_rcv.sb);
-
-	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
-
-	sbappendrecord(&so->so_rcv.sb, m);
-	sorwakeup(so);
-}
-
-/*
- * Implementation of usrreqs.
- */
-static void
-sco_sdetach(netmsg_t msg)
-{
-	struct socket *so = msg->detach.base.nm_so;
-	int error;
-
-	error = sco_detach((struct sco_pcb **)&so->so_pcb);
-	lwkt_replymsg(&msg->detach.base.lmsg, error);
-}
-
-/*
- * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
- *	 will sofree() it when we return.
- */
-static void
-sco_sabort (netmsg_t msg)
-{
-	struct socket *so = msg->abort.base.nm_so;
-	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-
-	sco_disconnect(pcb, 0);
-	soisdisconnected(so);
-	sco_sdetach(msg);
-	/* msg invalid now */
-}
-
-static void
-sco_sdisconnect (netmsg_t msg)
-{
-	struct socket *so = msg->abort.base.nm_so;
- 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	int error;
-
-	soisdisconnecting(so);
-
-	error = sco_disconnect(pcb, so->so_linger);
-	lwkt_replymsg(&msg->disconnect.base.lmsg, error);
-}
-
-static void
-sco_sattach(netmsg_t msg)
-{
-	struct socket *so = msg->attach.base.nm_so;
-	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	int error;
-
-	if (pcb) {
-		error = EINVAL;
-	} else {
-		error = soreserve(so, sco_sendspace, sco_recvspace,NULL);
-		if (error == 0) {
-			error = sco_attach((struct sco_pcb **)&so->so_pcb,
-					   &sco_proto, so);
-		}
-	}
-	lwkt_replymsg(&msg->attach.base.lmsg, error);
-}
-
-static void
-sco_sbind(netmsg_t msg)
-{
-	struct socket *so = msg->bind.base.nm_so;
-	struct sockaddr *nam = msg->bind.nm_nam;
-	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	struct sockaddr_bt *sa;
-	int error;
-
-	KKASSERT(nam != NULL);
-	sa = (struct sockaddr_bt *)nam;
-
-	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
-		error = EINVAL;
-	} else if (sa->bt_family != AF_BLUETOOTH) {
-		error = EAFNOSUPPORT;
-	} else {
-		error = sco_bind(pcb, sa);
-	}
-	lwkt_replymsg(&msg->bind.base.lmsg, error);
-}
-
-static void
-sco_sconnect(netmsg_t msg)
-{
-	struct socket *so = msg->connect.base.nm_so;
-	struct sockaddr *nam = msg->connect.nm_nam;
-	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	struct sockaddr_bt *sa;
-	int error;
-
-	KKASSERT(nam != NULL);
-	sa = (struct sockaddr_bt *)nam;
-
-	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
-		error = EINVAL;
-	} else if (sa->bt_family != AF_BLUETOOTH) {
-		error = EAFNOSUPPORT;
-	} else {
-		soisconnecting(so);
-		error = sco_connect(pcb, sa);
-	}
-	lwkt_replymsg(&msg->connect.base.lmsg, error);
-}
-
-static void
-sco_speeraddr(netmsg_t msg)
-{
-	struct socket *so = msg->peeraddr.base.nm_so;
-	struct sockaddr **nam = msg->peeraddr.nm_nam;
-	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	struct sockaddr_bt *sa, ssa;
-	int error;
-
-	sa = &ssa;
-	bzero(sa, sizeof *sa);
-	sa->bt_len = sizeof(struct sockaddr_bt);
-	sa->bt_family = AF_BLUETOOTH;
-	error = sco_peeraddr(pcb, sa);
-	*nam = dup_sockaddr((struct sockaddr *)sa);
-	lwkt_replymsg(&msg->peeraddr.base.lmsg, error);
-}
-
-static void
-sco_ssockaddr(netmsg_t msg)
-{
-	struct socket *so = msg->sockaddr.base.nm_so;
-	struct sockaddr **nam = msg->sockaddr.nm_nam;
-	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	struct sockaddr_bt *sa, ssa;
-	int error;
-
-	sa = &ssa;
-	bzero(sa, sizeof *sa);
-	sa->bt_len = sizeof(struct sockaddr_bt);
-	sa->bt_family = AF_BLUETOOTH;
-	error = sco_sockaddr(pcb, sa);
-	*nam = dup_sockaddr((struct sockaddr *)sa);
-
-	lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
-}
-
-static void
-sco_sshutdown(netmsg_t msg)
-{
-	socantsendmore(msg->shutdown.base.nm_so);
-	lwkt_replymsg(&msg->shutdown.base.lmsg, 0);
-}
-
-static void
-sco_ssend(netmsg_t msg)
-{
-	struct socket *so = msg->send.base.nm_so;
-	struct mbuf *m = msg->send.nm_m;
-	struct mbuf *control = msg->send.nm_control;
-	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	struct mbuf *m0;
-	int error = 0;
-
-	KKASSERT(m != NULL);
-	if (m->m_pkthdr.len == 0)
-		goto out;
-
-	if (m->m_pkthdr.len > pcb->sp_mtu) {
-		error = EMSGSIZE;
-		goto out;
-	}
-
-	m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
-	if (m0 == NULL) {
-		error = ENOMEM;
-		goto out;
-	}
-
-	/* no use for that */
-	if (control) {
-		m_freem(control);
-		control = NULL;
-	}
-
-	sbappendrecord(&so->so_snd.sb, m);
-	error = sco_send(pcb, m0);
-	m = NULL;
-out:
-	if (m)
-		m_freem(m);
-	if (control)
-		m_freem(control);
-	lwkt_replymsg(&msg->send.base.lmsg, error);
-}
-
-static void
-sco_saccept(netmsg_t msg)
-{
-	struct socket *so = msg->accept.base.nm_so;
-	struct sockaddr **nam = msg->accept.nm_nam;
-	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	struct sockaddr_bt *sa, ssa;
-	int error;
-
-	sa = &ssa;
-	bzero(sa, sizeof *sa);
-	sa->bt_len = sizeof(struct sockaddr_bt);
-	sa->bt_family = AF_BLUETOOTH;
-	error = sco_peeraddr(pcb, sa);
-	*nam = dup_sockaddr((struct sockaddr *)sa);
-
-	lwkt_replymsg(&msg->accept.base.lmsg, error);
-}
-
-static void
-sco_slisten(netmsg_t msg)
-{
-	struct socket *so = msg->listen.base.nm_so;
-	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	int error;
-
-	error = sco_listen(pcb);
-	lwkt_replymsg(&msg->accept.base.lmsg, error);
-}
-
-struct pr_usrreqs sco_usrreqs = {
-        .pru_abort = sco_sabort,
-        .pru_accept = sco_saccept,
-        .pru_attach = sco_sattach,
-        .pru_bind = sco_sbind,
-        .pru_connect = sco_sconnect,
-        .pru_connect2 = pr_generic_notsupp,
-        .pru_control = pr_generic_notsupp,
-        .pru_detach = sco_sdetach,
-        .pru_disconnect = sco_sdisconnect,
-        .pru_listen = sco_slisten,
-        .pru_peeraddr = sco_speeraddr,
-        .pru_rcvd = pr_generic_notsupp,
-        .pru_rcvoob = pr_generic_notsupp,
-        .pru_send = sco_ssend,
-        .pru_sense = pru_sense_null,
-        .pru_shutdown = sco_sshutdown,
-        .pru_sockaddr = sco_ssockaddr,
-        .pru_sosend = sosend,
-        .pru_soreceive = soreceive
-};
diff --git a/sys/netbt/sco_upper.c b/sys/netbt/sco_upper.c
deleted file mode 100644
index ecbf93d793..0000000000
--- a/sys/netbt/sco_upper.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/* $OpenBSD: sco_upper.c,v 1.2 2007/10/01 16:39:30 krw Exp $ */
-/* $NetBSD: sco_upper.c,v 1.6 2007/03/30 20:47:03 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/proc.h>
-#include <sys/systm.h>
-#include <sys/endian.h>
-#include <sys/bus.h>
-
-#include <netbt/bluetooth.h>
-#include <netbt/hci.h>
-#include <netbt/sco.h>
-
-/****************************************************************************
- *
- *	SCO - Upper Protocol API
- */
-
-struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb);
-
-/*
- * sco_attach(handle, proto, upper)
- *
- *	Attach a new instance of SCO pcb to handle
- */
-int
-sco_attach(struct sco_pcb **handle,
-		const struct btproto *proto, void *upper)
-{
-	struct sco_pcb *pcb;
-
-	KKASSERT(handle != NULL);
-	KKASSERT(proto != NULL);
-	KKASSERT(upper != NULL);
-
-	pcb = kmalloc(sizeof(*pcb), M_BLUETOOTH, M_NOWAIT | M_ZERO);
-	if (pcb == NULL)
-		return ENOMEM;
-
-	pcb->sp_proto = proto;
-	pcb->sp_upper = upper;
-
-	LIST_INSERT_HEAD(&sco_pcb, pcb, sp_next);
-
-	*handle = pcb;
-	return 0;
-}
-
-/*
- * sco_bind(pcb, sockaddr)
- *
- *	Bind SCO pcb to local address
- */
-int
-sco_bind(struct sco_pcb *pcb, struct sockaddr_bt *addr)
-{
-
-	bdaddr_copy(&pcb->sp_laddr, &addr->bt_bdaddr);
-	return 0;
-}
-
-/*
- * sco_sockaddr(pcb, sockaddr)
- *
- *	Copy local address of PCB to sockaddr
- */
-int
-sco_sockaddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
-{
-
-	memset(addr, 0, sizeof(struct sockaddr_bt));
-	addr->bt_len = sizeof(struct sockaddr_bt);
-	addr->bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_laddr);
-	return 0;
-}
-
-/*
- * sco_connect(pcb, sockaddr)
- *
- *	Initiate a SCO connection to the destination address.
- */
-int
-sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest)
-{
-	hci_add_sco_con_cp cp;
-	struct hci_unit *unit;
-	struct hci_link *acl, *sco;
-	int err;
-
-	if (pcb->sp_flags & SP_LISTENING)
-		return EINVAL;
-
-	bdaddr_copy(&pcb->sp_raddr, &dest->bt_bdaddr);
-
-	if (bdaddr_any(&pcb->sp_raddr))
-		return EDESTADDRREQ;
-
-	if (bdaddr_any(&pcb->sp_laddr)) {
-		err = hci_route_lookup(&pcb->sp_laddr, &pcb->sp_raddr);
-		if (err)
-			return err;
-	}
-
-	unit = hci_unit_lookup(&pcb->sp_laddr);
-	if (unit == NULL)
-		return ENETDOWN;
-
-	/*
-	 * We must have an already open ACL connection before we open the SCO
-	 * connection, and since SCO connections dont happen on their own we
-	 * will not open one, the application wanting this should have opened
-	 * it previously.
-	 */
-	acl = hci_link_lookup_bdaddr(unit, &pcb->sp_raddr, HCI_LINK_ACL);
-	if (acl == NULL || acl->hl_state != HCI_LINK_OPEN)
-		return EHOSTUNREACH;
-
-	sco = hci_link_alloc(unit);
-	if (sco == NULL)
-		return ENOMEM;
-
-	sco->hl_type = HCI_LINK_SCO;
-	bdaddr_copy(&sco->hl_bdaddr, &pcb->sp_raddr);
-
-	sco->hl_link = hci_acl_open(unit, &pcb->sp_raddr);
-	KKASSERT(sco->hl_link == acl);
-
-	cp.con_handle = htole16(acl->hl_handle);
-	cp.pkt_type = htole16(0x00e0);		/* HV1, HV2, HV3 */
-	err = hci_send_cmd(unit, HCI_CMD_ADD_SCO_CON, &cp, sizeof(cp));
-	if (err) {
-		hci_link_free(sco, err);
-		return err;
-	}
-
-	sco->hl_sco = pcb;
-	pcb->sp_link = sco;
-
-	pcb->sp_mtu = unit->hci_max_sco_size;
-	return 0;
-}
-
-/*
- * sco_peeraddr(pcb, sockaddr)
- *
- *	Copy remote address of SCO pcb to sockaddr
- */
-int
-sco_peeraddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
-{
-
-	memset(addr, 0, sizeof(struct sockaddr_bt));
-	addr->bt_len = sizeof(struct sockaddr_bt);
-	addr->bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_raddr);
-	return 0;
-}
-
-/*
- * sco_disconnect(pcb, linger)
- *
- *	Initiate disconnection of connected SCO pcb
- */
-int
-sco_disconnect(struct sco_pcb *pcb, int linger)
-{
-	hci_discon_cp cp;
-	struct hci_link *sco;
-	int err;
-
-	sco = pcb->sp_link;
-	if (sco == NULL)
-		return EINVAL;
-
-	cp.con_handle = htole16(sco->hl_handle);
-	cp.reason = 0x13;	/* "Remote User Terminated Connection" */
-
-	err = hci_send_cmd(sco->hl_unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp));
-	if (err || linger == 0) {
-		sco->hl_sco = NULL;
-		pcb->sp_link = NULL;
-		hci_link_free(sco, err);
-	}
-
-	return err;
-}
-
-/*
- * sco_detach(handle)
- *
- *	Detach SCO pcb from handle and clear up
- */
-int
-sco_detach(struct sco_pcb **handle)
-{
-	struct sco_pcb *pcb;
-
-	KKASSERT(handle != NULL);
-	pcb = *handle;
-	*handle = NULL;
-
-	if (pcb == NULL)
-		return EINVAL;
-
-	if (pcb->sp_link != NULL) {
-		sco_disconnect(pcb, 0);
-		pcb->sp_link = NULL;
-	}
-
-	LIST_REMOVE(pcb, sp_next);
-	kfree(pcb, M_BLUETOOTH);
-	return 0;
-}
-
-/*
- * sco_listen(pcb)
- *
- *	Mark pcb as a listener.
- */
-int
-sco_listen(struct sco_pcb *pcb)
-{
-
-	if (pcb->sp_link != NULL)
-		return EINVAL;
-
-	pcb->sp_flags |= SP_LISTENING;
-	return 0;
-}
-
-/*
- * sco_send(pcb, mbuf)
- *
- *	Send data on SCO pcb.
- *
- * Gross hackage, we just output the packet directly onto the unit queue.
- * This will work fine for one channel per unit, but for more channels it
- * really needs fixing. We set the context so that when the packet is sent,
- * we can drop a record from the socket buffer.
- */
-int
-sco_send(struct sco_pcb *pcb, struct mbuf *m)
-{
-	hci_scodata_hdr_t *hdr;
-	int plen;
-
-	if (pcb->sp_link == NULL) {
-		m_freem(m);
-		return EINVAL;
-	}
-
-	plen = m->m_pkthdr.len;
-	DPRINTFN(10, "%d bytes\n", plen);
-
-	/*
-	 * This is a temporary limitation, as USB devices cannot
-	 * handle SCO packet sizes that are not an integer number
-	 * of Isochronous frames. See ubt(4)
-	 */
-	if (plen != pcb->sp_mtu) {
-		m_freem(m);
-		return EMSGSIZE;
-	}
-
-	M_PREPEND(m, sizeof(hci_scodata_hdr_t), M_NOWAIT);
-	if (m == NULL)
-		return ENOMEM;
-
-	hdr = mtod(m, hci_scodata_hdr_t *);
-	hdr->type = HCI_SCO_DATA_PKT;
-	hdr->con_handle = htole16(pcb->sp_link->hl_handle);
-	hdr->length = plen;
-
-	pcb->sp_pending++;
-	M_SETCTX(m, pcb->sp_link);
-	hci_output_sco(pcb->sp_link->hl_unit, m);
-
-	return 0;
-}
-
-/*
- * sco_setopt(pcb, option, addr)
- *
- *	Set SCO pcb options
- */
-int
-sco_setopt(struct sco_pcb *pcb, int opt, void *addr)
-{
-	int err = 0;
-
-	switch (opt) {
-	default:
-		err = ENOPROTOOPT;
-		break;
-	}
-
-	return err;
-}
-
-/*
- * sco_getopt(pcb, option, addr)
- *
- *	Get SCO pcb options
- */
-int
-sco_getopt(struct sco_pcb *pcb, int opt, void *addr)
-{
-
-	switch (opt) {
-	case SO_SCO_MTU:
-		*(uint16_t *)addr = pcb->sp_mtu;
-		return sizeof(uint16_t);
-
-	case SO_SCO_HANDLE:
-		if (pcb->sp_link) {
-			*(uint16_t *)addr = pcb->sp_link->hl_handle;
-			return sizeof(uint16_t);
-		}
-		break;
-
-	default:
-		break;
-	}
-	return 0;
-}
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index 43660f29ca..5f0501352d 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -18,7 +18,8 @@ SUBDIR=	alias \
 	bmake \
 	brandelf \
 	bsdcat \
-	btpin \
+	bthost \
+	btsockstat \
 	bzip2 \
 	bzip2recover \
 	c89 \
@@ -167,7 +168,6 @@ SUBDIR=	alias \
 	rwho \
 	scp \
 	script \
-	sdpquery \
 	sed \
 	seq \
 	sftp \
diff --git a/usr.bin/bthost/Makefile b/usr.bin/bthost/Makefile
new file mode 100644
index 0000000000..27b14428fc
--- /dev/null
+++ b/usr.bin/bthost/Makefile
@@ -0,0 +1,9 @@
+# $Id: Makefile,v 1.4 2003/08/14 20:07:13 max Exp $
+# $FreeBSD: head/usr.bin/bluetooth/bthost/Makefile 201386 2010-01-02 10:27:05Z ed $
+
+PROG=		bthost
+
+DPADD=		${LIBBLUETOOTH}
+LDADD=		-lbluetooth 
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/bthost/bthost.1 b/usr.bin/bthost/bthost.1
new file mode 100644
index 0000000000..f86b6c469d
--- /dev/null
+++ b/usr.bin/bthost/bthost.1
@@ -0,0 +1,115 @@
+.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: bthost.1,v 1.7 2003/05/21 22:19:00 max Exp $
+.\" $FreeBSD: head/usr.bin/bluetooth/bthost/bthost.1 267773 2014-06-23 08:23:05Z bapt $
+.\"
+.Dd May 8, 2003
+.Dt BTHOST 1
+.Os
+.Sh NAME
+.Nm bthost
+.Nd look up Bluetooth host names and Protocol Service Multiplexor values
+.Sh SYNOPSIS
+.Nm
+.Op Fl bhp
+.Ar host_or_protocol
+.Sh DESCRIPTION
+The
+.Nm
+utility looks for information about Bluetooth hosts and
+Protocol Service Multiplexor (PSM) values.
+It gets this information from the
+.Pa /etc/bluetooth/hosts
+and
+.Pa /etc/bluetooth/protocols
+files.
+.Pp
+In host mode, it simply converts between the host names and Bluetooth addresses.
+The argument can be either a host name or a Bluetooth address.
+The program first attempts to interpret it as a Bluetooth address.
+If this fails, it will treat it as a host name.
+A Bluetooth address consists of six hex bytes separated by a colon,
+e.g.,
+.Dq Li 01:02:03:04:05:06 .
+A host name consists of names separated by dots, e.g.,
+.Dq Li my.cell.phone .
+.Pp
+In protocol mode, it simply converts between the Protocol Service Multiplexor
+names and assigned numbers.
+The argument can be either a Protocol Service Multiplexor name or
+an assigned number.
+The program first attempts to interpret it as an assigned number.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl b
+Produce brief output.
+.It Fl h
+Display usage message and exit.
+.It Fl p
+Activate protocol mode.
+.El
+.Pp
+The
+.Nm
+utility will print results to the standard output, and error messages to the
+standard error.
+An output can be quite different,
+here is an example that demonstrates all of the possibilities:
+.Bd -literal -offset indent
+% bthost localhost
+Host localhost has address FF:FF:FF:00:00:00
+% bthost ff:ff:ff:00:00:00
+Host FF:FF:FF:00:00:00 has name localhost
+% bthost -b localhost
+FF:FF:FF:00:00:00
+% bthost -b ff:ff:ff:00:00:00
+localhost
+% bthost do.not.exists
+do.not.exists: Unknown host
+% bthost 0:0:0:0:0:0
+00:00:00:00:00:00: Unknown host
+% bthost -p sdp
+Protocol/Service Multiplexor sdp has number 1
+% bthost -p 3
+Protocol/Service Multiplexor rfcomm has number 3
+% bthost -bp HID-Control
+17
+% bthost -p foo
+foo: Unknown Protocol/Service Multiplexor
+.Ed
+.Sh FILES
+.Bl -tag -width ".Pa /etc/bluetooth/hosts" -compact
+.It Pa /etc/bluetooth/hosts
+.It Pa /etc/bluetooth/protocols
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr bluetooth 3 ,
+.Xr bluetooth.hosts 5 ,
+.Xr bluetooth.protocols 5
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
diff --git a/usr.bin/bthost/bthost.c b/usr.bin/bthost/bthost.c
new file mode 100644
index 0000000000..72b5eb6d7a
--- /dev/null
+++ b/usr.bin/bthost/bthost.c
@@ -0,0 +1,142 @@
+/*
+ * bthost.c
+ *
+ * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: bthost.c,v 1.5 2003/05/21 20:30:01 max Exp $
+ * $FreeBSD: head/usr.bin/bluetooth/bthost/bthost.c 121054 2003-10-12 22:04:24Z emax $
+ */
+
+#include <bluetooth.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int  hostmode  (char const *arg, int brief);
+static int  protomode (char const *arg, int brief);
+static void usage     (void);
+
+int
+main(int argc, char **argv)
+{
+	int	opt, brief = 0, proto = 0;
+
+	while ((opt = getopt(argc, argv, "bhp")) != -1) {
+		switch (opt) {
+		case 'b':
+			brief = 1;
+			break;
+
+		case 'p':
+			proto = 1;
+			break;
+
+		case 'h':
+		default:
+			usage();
+			/* NOT REACHED */
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1)
+		usage();
+
+	exit(proto? protomode(*argv, brief) : hostmode(*argv, brief));
+}
+
+static int
+hostmode(char const *arg, int brief)
+{
+	struct hostent	*he = NULL;
+	bdaddr_t	 ba;
+	char		 bastr[32];
+	int		 reverse;
+
+	if (bt_aton(arg, &ba) == 1) {
+		reverse = 1;
+		he = bt_gethostbyaddr((char const *) &ba, sizeof(ba), 
+					AF_BLUETOOTH);
+	} else {
+		reverse = 0;
+		he = bt_gethostbyname(arg);
+	}
+
+	if (he == NULL) {
+		herror(reverse? bt_ntoa(&ba, bastr) : arg);
+		return (1);
+	}
+
+	if (brief)
+		printf("%s", reverse? he->h_name :
+				bt_ntoa((bdaddr_t *)(he->h_addr), bastr));
+	else
+		printf("Host %s has %s %s\n", 
+			reverse? bt_ntoa(&ba, bastr) : arg,
+			reverse? "name" : "address",
+			reverse? he->h_name :
+				bt_ntoa((bdaddr_t *)(he->h_addr), bastr));
+
+	return (0);
+}
+
+static int
+protomode(char const *arg, int brief)
+{
+	struct protoent	*pe = NULL;
+	int		 proto;
+
+	if ((proto = atoi(arg)) != 0)
+		pe = bt_getprotobynumber(proto);
+	else
+		pe = bt_getprotobyname(arg);
+
+	if (pe == NULL) {
+		fprintf(stderr, "%s: Unknown Protocol/Service Multiplexor\n", arg);
+		return (1);
+	}
+
+	if (brief) {
+		if (proto)
+			printf("%s", pe->p_name);
+		else
+			printf("%d", pe->p_proto);
+	} else {
+		printf("Protocol/Service Multiplexor %s has number %d\n",
+			pe->p_name, pe->p_proto);
+	}
+
+	return (0);
+}
+
+static void
+usage(void)
+{
+	fprintf(stdout, "Usage: bthost [-b -h -p] host_or_protocol\n");
+	exit(255);
+}
+
diff --git a/usr.bin/btpin/Makefile b/usr.bin/btpin/Makefile
deleted file mode 100644
index 54400c0ed5..0000000000
--- a/usr.bin/btpin/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# $NetBSD: Makefile,v 1.2 2006/09/26 19:18:19 plunky Exp $
-
-PROG=		btpin
-MAN=		btpin.1
-
-CFLAGS+=	-I${.CURDIR}/../../sys
-DPADD+=		${LIBBLUETOOTH}
-LDADD+=		-lbluetooth
-
-.include <bsd.prog.mk>
diff --git a/usr.bin/btpin/btpin.1 b/usr.bin/btpin/btpin.1
deleted file mode 100644
index 55a75172ad..0000000000
--- a/usr.bin/btpin/btpin.1
+++ /dev/null
@@ -1,92 +0,0 @@
-.\" $NetBSD: btpin.1,v 1.6 2007/09/24 19:29:01 plunky Exp $
-.\"
-.\" Copyright (c) 2006 Itronix Inc.
-.\" 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. The name of Itronix Inc. may not be used to endorse
-.\"    or promote products derived from this software without specific
-.\"    prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
-.\"
-.Dd September 24, 2007
-.Dt BTPIN 1
-.Os
-.Sh NAME
-.Nm btpin
-.Nd Bluetooth PIN utility
-.Sh SYNOPSIS
-.Nm
-.Op Fl d Ar device
-.Op Fl s Ar path
-.Brq Fl p Ar pin | Fl r Op Fl l Ar len
-.Fl a Ar address
-.Sh DESCRIPTION
-The
-.Nm
-utility is used to register a temporary PIN with the
-.Xr bthcid 8
-daemon for the purposes of pairing Bluetooth devices.
-The PIN will be valid for 5 minutes or until used, whichever comes first.
-.Pp
-The options are as follows:
-.Bl -tag -width indent
-.It Fl a Ar address
-Specify the remote device address.
-The address can be specified as BD_ADDR or a name.
-If a name was specified, the
-.Nm
-utility attempts to resolve the name via
-.Xr bt_gethostbyname 3 .
-.It Fl d Ar device
-Specify the local device address.
-The device can be specified by BD_ADDR or device name.
-See
-.Xr btconfig 8
-for a list of devices available.
-If no device is specified, the PIN will be valid for any local device.
-.It Fl l Ar len
-Specify length of PIN to generate, where 1 \*[Le]
-.Ar len
-\*[Le] 16.
-.It Fl p Ar pin
-The PIN to register.
-The PIN may be up to 16 bytes in length.
-.It Fl r
-Generate a random PIN, the default length is 4 bytes.
-.It Fl s Ar path
-Specify path to the control socket.
-The default path is
-.Pa /var/run/bthcid .
-.El
-.Sh FILES
-.Bl -item -compact
-.It
-.Pa /var/run/bthcid
-.El
-.Sh EXIT STATUS
-.Ex -std
-.Sh SEE ALSO
-.Xr btconfig 8 ,
-.Xr bthcid 8
-.Sh AUTHORS
-.An Iain Hibbert
-for Itronix, Inc
diff --git a/usr.bin/btpin/btpin.c b/usr.bin/btpin/btpin.c
deleted file mode 100644
index 8ff94e937b..0000000000
--- a/usr.bin/btpin/btpin.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* $NetBSD: btpin.c,v 1.3 2007/04/14 09:28:39 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/types.h>
-#include <sys/un.h>
-#include <bluetooth.h>
-#include <err.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-static void usage(void) __dead2;
-
-int
-main(int ac, char *av[])
-{
-	bthcid_pin_response_t rp;
-	struct sockaddr_un un;
-	char *pin = NULL;
-	int ch, s, len;
-
-	memset(&rp, 0, sizeof(rp));
-	len = -1;
-
-	memset(&un, 0, sizeof(un));
-	un.sun_len = sizeof(un);
-	un.sun_family = AF_LOCAL;
-	strlcpy(un.sun_path, BTHCID_SOCKET_NAME, sizeof(un.sun_path));
-
-	while ((ch = getopt(ac, av, "a:d:l:p:rs:")) != -1) {
-		switch (ch) {
-		case 'a':
-			if (!bt_aton(optarg, &rp.raddr)) {
-				struct hostent  *he = NULL;
-
-				if ((he = bt_gethostbyname(optarg)) == NULL)
-					errx(EXIT_FAILURE, "%s: %s", optarg,
-							hstrerror(h_errno));
-
-				bdaddr_copy(&rp.raddr, (bdaddr_t *)he->h_addr);
-			}
-			break;
-
-		case 'd':
-			if (!bt_devaddr(optarg, &rp.laddr))
-				err(EXIT_FAILURE, "%s", optarg);
-
-			break;
-
-		case 'l':
-			len = atoi(optarg);
-			if (len < 1 || len > HCI_PIN_SIZE)
-				errx(EXIT_FAILURE, "Invalid PIN length");
-
-			break;
-
-		case 'p':
-			pin = optarg;
-			break;
-
-		case 'r':
-			if (len == -1)
-				len = 4;
-
-			break;
-
-		case 's':
-			strlcpy(un.sun_path, optarg, sizeof(un.sun_path));
-			break;
-
-		default:
-			usage();
-		}
-	}
-
-	if (bdaddr_any(&rp.raddr))
-		usage();
-
-	if (pin == NULL) {
-		if (len == -1)
-			usage();
-
-		srandom(time(NULL));
-
-		pin = (char *)rp.pin;
-		while (len-- > 0)
-			*pin++ = '0' + (random() % 10);
-
-		printf("PIN: %.*s\n", HCI_PIN_SIZE, rp.pin);
-	} else {
-		if (len != -1)
-			usage();
-
-		strncpy((char *)rp.pin, pin, HCI_PIN_SIZE);
-	}
-
-	s = socket(PF_LOCAL, SOCK_STREAM, 0);
-	if (s < 0)
-		err(EXIT_FAILURE, "socket");
-
-	if (connect(s, (struct sockaddr *)&un, sizeof(un)) < 0)
-		err(EXIT_FAILURE, "connect(\"%s\")", un.sun_path);
-	
-	if (send(s, &rp, sizeof(rp), 0) != sizeof(rp))
-		err(EXIT_FAILURE, "send");
-
-	close(s);
-	exit(EXIT_SUCCESS);
-}
-
-static void
-usage(void)
-{
-
-	fprintf(stderr,
-		"usage: %s [-d device] [-s socket] {-p pin | -r [-l len]} -a addr\n"
-		"", getprogname());
-
-	exit(EXIT_FAILURE);
-}
diff --git a/usr.bin/btsockstat/Makefile b/usr.bin/btsockstat/Makefile
new file mode 100644
index 0000000000..baa14db7cf
--- /dev/null
+++ b/usr.bin/btsockstat/Makefile
@@ -0,0 +1,12 @@
+# $Id: Makefile,v 1.7 2003/08/14 20:07:14 max Exp $
+# $FreeBSD: head/usr.bin/bluetooth/btsockstat/Makefile 140941 2005-01-28 16:08:11Z ru $
+
+PROG=		btsockstat
+WARNS?=		2
+BINGRP=		kmem
+BINMODE=	2555
+
+DPADD=		${LIBBLUETOOTH} ${LIBKVM}
+LDADD=		-lbluetooth -lkvm
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/btsockstat/btsockstat.1 b/usr.bin/btsockstat/btsockstat.1
new file mode 100644
index 0000000000..9625a89a64
--- /dev/null
+++ b/usr.bin/btsockstat/btsockstat.1
@@ -0,0 +1,83 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: btsockstat.1,v 1.6 2003/05/21 00:09:45 max Exp $
+.\" $FreeBSD: head/usr.bin/bluetooth/btsockstat/btsockstat.1 267773 2014-06-23 08:23:05Z bapt $
+.\"
+.Dd October 12, 2003
+.Dt BTSOCKSTAT 1
+.Os
+.Sh NAME
+.Nm btsockstat
+.Nd show Bluetooth sockets information
+.Sh SYNOPSIS
+.Nm
+.Op Fl nrh
+.Op Fl M Ar core
+.Op Fl p Ar protocol
+.Sh DESCRIPTION
+The
+.Nm
+utility symbolically displays the contents of various Bluetooth sockets
+related data structures.
+There are few output formats, depending on the
+options for the information presented.
+The
+.Nm
+utility
+will print results to the standard output and error messages to the
+standard error.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl h
+Display usage message and exit.
+.It Fl M Ar core
+Extract values associated with the name list from the specified core
+instead of the default
+.Pa /dev/kmem .
+.It Fl n
+Show Bluetooth addresses as numbers.
+Normally,
+.Nm
+attempts to resolve Bluetooth addresses, and display them symbolically.
+.It Fl p Ar protocol
+Display a list of active sockets (protocol control blocks) for each
+specified protocol.
+Supported protocols are:
+.Cm hci_raw , l2cap_raw , l2cap, rfcomm
+and
+.Cm rfcomm_s .
+.It Fl r
+Display a list of active routing entries (if any) for specified protocol.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr ng_btsocket 4
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report if found.
diff --git a/usr.bin/btsockstat/btsockstat.c b/usr.bin/btsockstat/btsockstat.c
new file mode 100644
index 0000000000..2e1ae8fc0f
--- /dev/null
+++ b/usr.bin/btsockstat/btsockstat.c
@@ -0,0 +1,646 @@
+/*
+ * btsockstat.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: btsockstat.c,v 1.8 2003/05/21 22:40:25 max Exp $
+ * $FreeBSD: head/usr.bin/bluetooth/btsockstat/btsockstat.c 180964 2008-07-29 17:02:00Z emax $
+ */
+
+#define _KERNEL_STRUCTURES
+#include <sys/types.h>
+#include <sys/callout.h>
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <bluetooth.h>
+#include <err.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+
+#include <netgraph7/bluetooth/include/ng_bluetooth.h>
+#include <netgraph7/bluetooth/include/ng_btsocket_hci_raw.h>
+#include <netgraph7/bluetooth/include/ng_btsocket_l2cap.h>
+#include <netgraph7/bluetooth/include/ng_btsocket_rfcomm.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void	hcirawpr   (kvm_t *kvmd, u_long addr);
+static void	l2caprawpr (kvm_t *kvmd, u_long addr);
+static void	l2cappr    (kvm_t *kvmd, u_long addr);
+static void	l2caprtpr  (kvm_t *kvmd, u_long addr);
+static void	rfcommpr   (kvm_t *kvmd, u_long addr);
+static void	rfcommpr_s (kvm_t *kvmd, u_long addr);
+
+static char *	bdaddrpr   (bdaddr_p const ba, char *str, int len);
+
+static kvm_t *	kopen      (char const *memf);
+static int	kread      (kvm_t *kvmd, u_long addr, char *buffer, int size);
+
+static void	usage      (void);
+
+/*
+ * List of symbols
+ */
+
+static struct nlist	nl[] = {
+#define N_HCI_RAW	0
+	{ "_ng_btsocket_hci_raw_sockets" },
+#define N_L2CAP_RAW	1
+	{ "_ng_btsocket_l2cap_raw_sockets" },
+#define N_L2CAP		2
+	{ "_ng_btsocket_l2cap_sockets" },
+#define N_L2CAP_RAW_RT	3
+	{ "_ng_btsocket_l2cap_raw_rt" },
+#define N_L2CAP_RT	4
+	{ "_ng_btsocket_l2cap_rt" },
+#define N_RFCOMM	5
+	{ "_ng_btsocket_rfcomm_sockets" },
+#define N_RFCOMM_S	6
+	{ "_ng_btsocket_rfcomm_sessions" },
+	{ "" },
+};
+
+#define state2str(x) \
+	(((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
+
+/*
+ * Main
+ */
+
+static int	numeric_bdaddr = 0;
+
+int
+main(int argc, char *argv[])
+{
+	int	 opt, proto = -1, route = 0;
+	kvm_t	*kvmd = NULL;
+	char	*memf = NULL;
+
+	while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) {
+		switch (opt) {
+		case 'n':
+			numeric_bdaddr = 1;
+			break;
+
+		case 'M':
+			memf = optarg;
+			break;
+
+		case 'p':
+			if (strcasecmp(optarg, "hci_raw") == 0)
+				proto = N_HCI_RAW;
+			else if (strcasecmp(optarg, "l2cap_raw") == 0)
+				proto = N_L2CAP_RAW;
+			else if (strcasecmp(optarg, "l2cap") == 0)
+				proto = N_L2CAP;
+			else if (strcasecmp(optarg, "rfcomm") == 0)
+				proto = N_RFCOMM;
+			else if (strcasecmp(optarg, "rfcomm_s") == 0)
+				proto = N_RFCOMM_S; 
+			else
+				usage();
+				/* NOT REACHED */
+			break;
+
+		case 'r':
+			route = 1;
+			break;
+
+		case 'h':
+		default:
+			usage();
+			/* NOT REACHED */
+		}
+	}
+
+	if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
+		usage();
+		/* NOT REACHED */
+
+	/*
+	 * Discard setgid privileges if not the running kernel so that
+	 * bad guys can't print interesting stuff from kernel memory.
+	 */
+
+	if (memf != NULL)
+		setgid(getgid());
+
+	kvmd = kopen(memf);
+	if (kvmd == NULL)
+		return (1);
+
+	switch (proto) {
+	case N_HCI_RAW:
+		hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
+		break;
+
+	case N_L2CAP_RAW:
+		if (route)
+			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
+		else
+			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
+		break;
+
+	case N_L2CAP:
+		if (route) 
+			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
+		else
+			l2cappr(kvmd, nl[N_L2CAP].n_value);
+		break;
+
+	case N_RFCOMM:
+		rfcommpr(kvmd, nl[N_RFCOMM].n_value);
+		break;
+
+	case N_RFCOMM_S:
+		rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
+		break;
+
+	default:
+		if (route) {
+			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
+			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
+		} else {
+			hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
+			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
+			l2cappr(kvmd, nl[N_L2CAP].n_value);
+			rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
+			rfcommpr(kvmd, nl[N_RFCOMM].n_value);
+		}
+		break;
+	}
+
+	return (kvm_close(kvmd));
+} /* main */
+
+/*
+ * Print raw HCI sockets
+ */
+
+static void
+hcirawpr(kvm_t *kvmd, u_long addr)
+{
+	ng_btsocket_hci_raw_pcb_p	this = NULL, next = NULL;
+	ng_btsocket_hci_raw_pcb_t	pcb;
+	struct socket			so;
+	int				first = 1;
+
+	if (addr == 0)
+		return;
+
+        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+		return;
+
+	for ( ; this != NULL; this = next) {
+		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
+			return;
+		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
+			return;
+
+		next = LIST_NEXT(&pcb, next);
+
+		if (first) {
+			first = 0;
+			fprintf(stdout,
+"Active raw HCI sockets\n" \
+"%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
+				"Socket",
+				"PCB",
+				"Flags",
+				"Recv-Q",
+				"Send-Q",
+				"Local address");
+		}
+
+		if (pcb.addr.hci_node[0] == 0) {
+			pcb.addr.hci_node[0] = '*';
+			pcb.addr.hci_node[1] = 0;
+		}
+
+		fprintf(stdout,
+"%-8lx %-8lx %-6.6x %6lu %6lu %-16.16s\n",
+			(unsigned long) pcb.so,
+			(unsigned long) this,
+			pcb.flags,
+			so.so_rcv.sb.sb_cc,
+			so.so_snd.sb.sb_cc,
+			pcb.addr.hci_node);
+	}
+} /* hcirawpr */
+
+/*
+ * Print raw L2CAP sockets
+ */
+
+static void
+l2caprawpr(kvm_t *kvmd, u_long addr)
+{
+	ng_btsocket_l2cap_raw_pcb_p	this = NULL, next = NULL;
+	ng_btsocket_l2cap_raw_pcb_t	pcb;
+	struct socket			so;
+	int				first = 1;
+
+	if (addr == 0)
+		return;
+
+        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+		return;
+
+	for ( ; this != NULL; this = next) {
+		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
+			return;
+		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
+			return;
+
+		next = LIST_NEXT(&pcb, next);
+
+		if (first) {
+			first = 0;
+			fprintf(stdout, 
+"Active raw L2CAP sockets\n" \
+"%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
+				"Socket",
+				"PCB",
+				"Recv-Q",
+				"Send-Q",
+				"Local address");
+		}
+
+		fprintf(stdout,
+"%-8lx %-8lx %6lu %6lu %-17.17s\n",
+			(unsigned long) pcb.so,
+			(unsigned long) this,
+			so.so_rcv.sb.sb_cc,
+			so.so_snd.sb.sb_cc,
+			bdaddrpr(&pcb.src, NULL, 0));
+	}
+} /* l2caprawpr */
+
+/*
+ * Print L2CAP sockets
+ */
+
+static void
+l2cappr(kvm_t *kvmd, u_long addr)
+{
+	static char const * const	states[] = {
+	/* NG_BTSOCKET_L2CAP_CLOSED */		"CLOSED",
+	/* NG_BTSOCKET_L2CAP_CONNECTING */	"CON",
+	/* NG_BTSOCKET_L2CAP_CONFIGURING */	"CONFIG",
+	/* NG_BTSOCKET_L2CAP_OPEN */		"OPEN",
+	/* NG_BTSOCKET_L2CAP_DISCONNECTING */	"DISCON"
+	};
+
+	ng_btsocket_l2cap_pcb_p	this = NULL, next = NULL;
+	ng_btsocket_l2cap_pcb_t	pcb;
+	struct socket		so;
+	int			first = 1;
+	char			local[24], remote[24];
+
+	if (addr == 0)
+		return;
+
+        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+		return;
+
+	for ( ; this != NULL; this = next) {
+		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
+			return;
+		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
+			return;
+
+		next = LIST_NEXT(&pcb, next);
+
+		if (first) {
+			first = 0;
+			fprintf(stdout,
+"Active L2CAP sockets\n" \
+"%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
+				"PCB",
+				"Recv-Q",
+				"Send-Q",
+				"Local address/PSM",
+				"Foreign address",
+				"CID",
+				"State");
+		}
+
+		fprintf(stdout,
+"%-8lx %6lu %6lu %-17.17s/%-5d %-17.17s %-5d %s\n",
+			(unsigned long) this,
+			so.so_rcv.sb.sb_cc,
+			so.so_snd.sb.sb_cc,
+			bdaddrpr(&pcb.src, local, sizeof(local)),
+			pcb.psm,
+			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
+			pcb.cid,
+			(so.so_options & SO_ACCEPTCONN)?
+				"LISTEN" : state2str(pcb.state));
+	}
+} /* l2cappr */
+
+/*
+ * Print L2CAP routing table
+ */
+
+static void
+l2caprtpr(kvm_t *kvmd, u_long addr)
+{
+	ng_btsocket_l2cap_rtentry_p	this = NULL, next = NULL;
+	ng_btsocket_l2cap_rtentry_t	rt;
+	int				first = 1;
+
+	if (addr == 0)
+		return;
+
+	if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+		return;
+
+	for ( ; this != NULL; this = next) {
+		if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
+			return;
+
+		next = LIST_NEXT(&rt, next);
+
+		if (first) {
+			first = 0;
+			fprintf(stdout,
+"Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)?  "raw " : "");
+			fprintf(stdout,
+"%-8.8s %-8.8s %-17.17s\n",	"RTentry",
+				"Hook",
+				"BD_ADDR");
+		}
+
+		fprintf(stdout,
+"%-8lx %-8lx %-17.17s\n",
+			(unsigned long) this,
+			(unsigned long) rt.hook,
+			bdaddrpr(&rt.src, NULL, 0));
+	}
+} /* l2caprtpr */
+
+/*
+ * Print RFCOMM sockets
+ */
+
+static void
+rfcommpr(kvm_t *kvmd, u_long addr)
+{
+	static char const * const	states[] = {
+	/* NG_BTSOCKET_RFCOMM_DLC_CLOSED */	   "CLOSED",
+	/* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */	   "W4CON",
+	/* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */   "CONFIG",
+	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */    "CONN",
+	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */     "OPEN",
+	/* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
+	};
+
+	ng_btsocket_rfcomm_pcb_p	this = NULL, next = NULL;
+	ng_btsocket_rfcomm_pcb_t	pcb;
+	struct socket			so;
+	int				first = 1;
+	char				local[24], remote[24];
+
+	if (addr == 0)
+		return;
+
+        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+		return;
+
+	for ( ; this != NULL; this = next) {
+		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
+			return;
+		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
+			return;
+
+		next = LIST_NEXT(&pcb, next);
+
+		if (first) {
+			first = 0;
+			fprintf(stdout,
+"Active RFCOMM sockets\n" \
+"%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
+				"PCB",
+				"Recv-Q",
+				"Send-Q",
+				"Local address",
+				"Foreign address",
+				"Chan",
+				"DLCI",
+				"State");
+		}
+
+		fprintf(stdout,
+"%-8lx %6lu %6lu %-17.17s %-17.17s %-4d %-4d %s\n",
+			(unsigned long) this,
+			so.so_rcv.sb.sb_cc,
+			so.so_snd.sb.sb_cc,
+			bdaddrpr(&pcb.src, local, sizeof(local)),
+			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
+			pcb.channel,
+			pcb.dlci,
+			(so.so_options & SO_ACCEPTCONN)?
+				"LISTEN" : state2str(pcb.state));
+	}
+} /* rfcommpr */
+
+/*
+ * Print RFCOMM sessions
+ */
+
+static void
+rfcommpr_s(kvm_t *kvmd, u_long addr)
+{
+	static char const * const	states[] = {
+	/* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */	       "CLOSED",
+	/* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */     "LISTEN",
+	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */    "CONNECTING",
+	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */     "CONNECTED",
+	/* NG_BTSOCKET_RFCOMM_SESSION_OPEN */          "OPEN",
+	/* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
+	};
+
+	ng_btsocket_rfcomm_session_p	this = NULL, next = NULL;
+	ng_btsocket_rfcomm_session_t	s;
+	struct socket			so;
+	int				first = 1;
+
+	if (addr == 0)
+		return;
+
+        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+		return;
+
+	for ( ; this != NULL; this = next) {
+		if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
+			return;
+		if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
+			return;
+
+		next = LIST_NEXT(&s, next);
+
+		if (first) {
+			first = 0;
+			fprintf(stdout,
+"Active RFCOMM sessions\n" \
+"%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
+				"L2PCB",
+				"PCB",
+				"Flags",
+				"MTU",
+				"Out-Q",
+				"DLCs",
+				"State");
+		}
+
+		fprintf(stdout,
+"%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n",
+			(unsigned long) so.so_pcb,
+			(unsigned long) this,
+			s.flags,
+			s.mtu,
+			s.outq.len,
+			LIST_EMPTY(&s.dlcs)? "No" : "Yes",
+			state2str(s.state));
+	}
+} /* rfcommpr_s */
+
+/*
+ * Return BD_ADDR as string
+ */
+
+static char *
+bdaddrpr(bdaddr_p const ba, char *str, int len)
+{
+	static char	 buffer[MAXHOSTNAMELEN];
+	struct hostent	*he = NULL;
+
+	if (str == NULL) {
+		str = buffer;
+		len = sizeof(buffer);
+	}
+
+	if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
+		str[0] = '*';
+		str[1] = 0;
+
+		return (str);
+	}
+
+	if (!numeric_bdaddr &&
+	    (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
+		strlcpy(str, he->h_name, len);
+
+		return (str);
+	}
+
+	bt_ntoa(ba, str);
+
+	return (str);
+} /* bdaddrpr */
+
+/*
+ * Open kvm
+ */
+
+static kvm_t *
+kopen(char const *memf)
+{
+	kvm_t	*kvmd = NULL;
+	char	 errbuf[_POSIX2_LINE_MAX];
+
+	/*
+	 * Discard setgid privileges if not the running kernel so that 
+	 * bad guys can't print interesting stuff from kernel memory.
+	 */
+
+	if (memf != NULL)
+		setgid(getgid());   
+
+	kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
+	if (kvmd == NULL) {
+		warnx("kvm_openfiles: %s", errbuf);
+		return (NULL);
+	}
+
+	if (kvm_nlist(kvmd, nl) < 0) {
+		warnx("kvm_nlist: %s", kvm_geterr(kvmd));
+		goto fail;
+	}
+
+	if (nl[0].n_type == 0) {
+		warnx("kvm_nlist: no namelist");
+		goto fail;
+	}
+
+	return (kvmd);
+fail:
+	kvm_close(kvmd);
+
+	return (NULL);
+} /* kopen */
+
+/*
+ * Read kvm
+ */
+
+static int
+kread(kvm_t *kvmd, u_long addr, char *buffer, int size)
+{
+	if (kvmd == NULL || buffer == NULL)
+		return (-1);
+
+	if (kvm_read(kvmd, addr, buffer, size) != size) {
+		warnx("kvm_read: %s", kvm_geterr(kvmd));
+		return (-1);
+	}
+
+	return (0);
+} /* kread */
+
+/*
+ * Print usage and exit
+ */
+
+static void
+usage(void)
+{
+	fprintf(stdout, "Usage: btsockstat [-M core ] [-n] [-p proto] [-r]\n");
+	exit(255);
+} /* usage */
+
diff --git a/usr.bin/rfcomm_sppd/Makefile b/usr.bin/rfcomm_sppd/Makefile
index 79357e15cf..fbd15119e7 100644
--- a/usr.bin/rfcomm_sppd/Makefile
+++ b/usr.bin/rfcomm_sppd/Makefile
@@ -1,11 +1,11 @@
-# $NetBSD: Makefile,v 1.2 2007/05/28 12:06:29 tls Exp $
-# $DragonFly: src/usr.bin/rfcomm_sppd/Makefile,v 1.1 2008/02/08 14:06:25 hasso Exp $
+# $Id: Makefile,v 1.7 2003/09/07 18:15:55 max Exp $
+# $FreeBSD: head/usr.bin/bluetooth/rfcomm_sppd/Makefile 140941 2005-01-28 16:08:11Z ru $
 
 PROG=		rfcomm_sppd
 SRCS=		rfcomm_sppd.c rfcomm_sdp.c
+WARNS?=		2
 
-CFLAGS+=	-I${.CURDIR}/../../sys
-DPADD+=		${LIBBLUETOOTH} ${LIBSDP}
-LDADD+=		-lbluetooth -lsdp
+DPADD=		${LIBBLUETOOTH} ${LIBSDP}
+LDADD=		-lbluetooth -lsdp
 
 .include <bsd.prog.mk>
diff --git a/usr.bin/rfcomm_sppd/rfcomm_sdp.c b/usr.bin/rfcomm_sppd/rfcomm_sdp.c
index 6a3834b3d8..1b61ea9e20 100644
--- a/usr.bin/rfcomm_sppd/rfcomm_sdp.c
+++ b/usr.bin/rfcomm_sppd/rfcomm_sdp.c
@@ -1,34 +1,3 @@
-/* $NetBSD: rfcomm_sdp.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
-/* $DragonFly: src/usr.bin/rfcomm_sppd/rfcomm_sdp.c,v 1.1 2008/02/08 14:06:25 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
 /*
  * rfcomm_sdp.c
  *
@@ -56,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: rfcomm_sdp.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $
- * $FreeBSD: src/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c,v 1.2 2004/04/09 23:26:16 emax Exp $
+ * $Id: rfcomm_sdp.c,v 1.1 2003/09/07 18:15:55 max Exp $
+ * $FreeBSD: head/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c 128077 2004-04-09 23:26:16Z emax $
  */
 
 #include <bluetooth.h>
@@ -65,8 +34,6 @@
 #include <sdp.h>
 #include <stdio.h>
 
-#include "rfcomm_sdp.h"
-
 #undef	PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE
 #define	PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE	256
 
@@ -74,7 +41,7 @@
 #define	PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE	12
 
 static int rfcomm_proto_list_parse (uint8_t const *start, uint8_t const *end,
-					uint8_t *channel, int *error);
+					int *channel, int *error);
 
 /*
  * Lookup RFCOMM channel number in the Protocol Descriptor List
@@ -93,7 +60,7 @@ static int rfcomm_proto_list_parse (uint8_t const *start, uint8_t const *end,
 
 int
 rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,
-			int service, uint8_t *channel, int *error)
+			int service, int *channel, int *error)
 {
 	uint8_t		 buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE];
 	void		*ss    = NULL;
@@ -105,7 +72,7 @@ rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,
 	uint32_t	 type, len;
 
 	if (local == NULL)
-		local = BDADDR_ANY;
+		local = NG_HCI_BDADDR_ANY;
 	if (remote == NULL || channel == NULL)
 		rfcomm_channel_lookup_exit(EINVAL);
 
@@ -123,7 +90,7 @@ rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,
 	ss = NULL;
 
 	/*
-	 * If it is possible for more than one kind of protocol stack to be
+	 * If it is possible for more than one kind of protocol stack to be 
 	 * used to gain access to the service, the ProtocolDescriptorList
 	 * takes the form of a data element alternative. We always use the
 	 * first protocol stack.
@@ -136,11 +103,11 @@ rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,
 	 *		uuid16 value16	- 3 bytes	L2CAP
 	 *	seq8 len8		- 2 bytes
 	 *		uuid16 value16	- 3 bytes	RFCOMM
-	 *		uint8  value8	- 2 bytes	RFCOMM param #1
+	 *		uint8  value8	- 2 bytes	RFCOMM param #1 
 	 *				=========
 	 *				 14 bytes
 	 *
-	 * Lets not count first [seq8 len8] wrapper, so the minimal size of
+	 * Lets not count first [seq8 len8] wrapper, so the minimal size of 
 	 * the Protocol Descriptor List (the data we are actually interested
 	 * in) for RFCOMM based service would be 12 bytes.
 	 */
@@ -186,14 +153,14 @@ rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,
 	return (rfcomm_proto_list_parse(proto.value,
 					buffer + proto.vlen, channel, error));
 }
-
+	
 /*
  * Parse protocol descriptor list
  *
  * The ProtocolDescriptorList attribute describes one or more protocol
- * stacks that may be used to gain access to the service described by
+ * stacks that may be used to gain access to the service described by 
  * the service record. If the ProtocolDescriptorList describes a single
- * stack, it takes the form of a data element sequence in which each
+ * stack, it takes the form of a data element sequence in which each 
  * element of the sequence is a protocol descriptor.
  */
 
@@ -206,21 +173,21 @@ rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,
 
 static int
 rfcomm_proto_list_parse(uint8_t const *start, uint8_t const *end,
-			uint8_t *channel, int *error)
+			int *channel, int *error)
 {
 	int	type, len, value;
 
 	while (start < end) {
 
-		/*
+		/* 
 		 * Parse protocol descriptor
 		 *
-		 * A protocol descriptor identifies a communications protocol
-		 * and provides protocol specific parameters. A protocol
-		 * descriptor is represented as a data element sequence. The
-		 * first data element in the sequence must be the UUID that
+		 * A protocol descriptor identifies a communications protocol 
+		 * and provides protocol specific parameters. A protocol 
+		 * descriptor is represented as a data element sequence. The 
+		 * first data element in the sequence must be the UUID that 
 		 * identifies the protocol. Additional data elements optionally
-		 * provide protocol specific information, such as the L2CAP
+		 * provide protocol specific information, such as the L2CAP 
 		 * protocol/service multiplexer (PSM) and the RFCOMM server
 		 * channel number (CN).
 		 */
@@ -290,9 +257,10 @@ rfcomm_proto_list_parse(uint8_t const *start, uint8_t const *end,
 	}
 
 	/*
-	 * If we got here then it means we could not find RFCOMM protocol
+	 * If we got here then it means we could not find RFCOMM protocol 
 	 * descriptor, but the reply format was actually valid.
 	 */
 
 	rfcomm_proto_list_parse_exit(ENOATTR);
 }
+
diff --git a/usr.bin/rfcomm_sppd/rfcomm_sdp.h b/usr.bin/rfcomm_sppd/rfcomm_sdp.h
deleted file mode 100644
index dea37dc8bb..0000000000
--- a/usr.bin/rfcomm_sppd/rfcomm_sdp.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* $NetBSD: rfcomm_sdp.h,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
-/* $DragonFly: src/usr.bin/rfcomm_sppd/rfcomm_sdp.h,v 1.1 2008/02/08 14:06:25 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
-
-#ifndef _RFCOMM_SDP_H_
-#define _RFCOMM_SDP_H_
-
-int rfcomm_channel_lookup(bdaddr_t const *, bdaddr_t const *, int, uint8_t *, int *);
-
-#endif	/* _RFCOMM_SDP_H */
diff --git a/usr.bin/rfcomm_sppd/rfcomm_sppd.1 b/usr.bin/rfcomm_sppd/rfcomm_sppd.1
index 66157a614f..d94883b1fa 100644
--- a/usr.bin/rfcomm_sppd/rfcomm_sppd.1
+++ b/usr.bin/rfcomm_sppd/rfcomm_sppd.1
@@ -1,33 +1,3 @@
-.\" $NetBSD: rfcomm_sppd.1,v 1.5 2007/04/21 06:15:23 plunky Exp $
-.\"
-.\" Copyright (c) 2006 Itronix Inc.
-.\" 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. The name of Itronix Inc. may not be used to endorse
-.\"    or promote products derived from this software without specific
-.\"    prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 Maksim Yevmenkin <m_evmenkin@yahoo.com>
 .\" All rights reserved.
 .\"
@@ -52,6 +22,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
+.\" $Id: rfcomm_sppd.1,v 1.3 2003/09/07 18:15:55 max Exp $
+.\" $FreeBSD: head/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.1 267773 2014-06-23 08:23:05Z bapt $
+.\"
 .Dd October 17, 2017
 .Dt RFCOMM_SPPD 1
 .Os
@@ -60,104 +33,125 @@
 .Nd RFCOMM Serial Port Profile daemon
 .Sh SYNOPSIS
 .Nm
-.Op Fl d Ar device
-.Op Fl m Ar mode
-.Op Fl s Ar service
+.Op Fl bhS
+.Fl a Ar address
+.Fl c Ar channel
 .Op Fl t Ar tty
-.Brq Fl a Ar address | Fl c Ar channel
 .Sh DESCRIPTION
 The
 .Nm
-utility is a Serial Port Profile daemon, providing serial access over
-an RFCOMM connection to a remote device.
-.Nm
-can work in client or server mode.
+utility is a Serial Port Profile daemon.
+It can operate in two modes: client and server.
 .Pp
 In client mode,
 .Nm
-initiates an RFCOMM connection to the
-.Ar service
-at the remote
-.Ar address .
+opens RFCOMM connection to the specified
+.Ar address
+server and
+.Ar channel .
+Once connection is established, the
+.Nm
+utility provides access to the server's remote serial port via stdin/stdout
+or via
+.Xr pty 4
+interface if
+.Fl t
+option was specified.
 .Pp
-In server mode,
+If the
+.Fl S
+option is specified,
+.Nm
+will operate in server mode and act as RFCOMM server,
+listening on
+.Dv ANY
+address and advertising a virtual serial port
+via the
+.Xr sdpd 8
+daemon.
+If
+.Fl t
+options was specified,
+the server side of the virtual serial port is attached to the pseudo-terminal
+.Ar tty .
+Otherwise the virtual serial port is attached to the stdin/stdout.
 .Nm
-registers the
-.Ar service
-with the local SDP server and listens on the specified RFCOMM
-.Ar channel
-for an incoming connection.
+should be run as root in order to communicate with
+.Xr sdpd 8
+in this case.
+.Pp
+The
+.Nm
+utility opens both master and slave pseudo terminals.
+This is done to ensure that RFCOMM connection stays open until
+.Nm
+is terminated.
+The data received from the master pseudo terminal are sent over
+the RFCOMM connection.
+The data received from the RFCOMM connection are written
+into master pseudo terminal.
+The application in its turn opens the slave pseudo
+terminal and operates on it just like it would operate over the standard serial
+port.
 .Pp
 The options are as follows:
-.Bl -tag -width ".Fl c Ar channel"
+.Bl -tag -width indent
 .It Fl a Ar address
-Client mode.
-Specify the address of the remote RFCOMM device.
+In client mode,
+this required option specifies the address of the remote RFCOMM server.
+If this option is specified in server mode,
+.Nm
+will only accept connections from the
+.Tn Bluetooth
+device with address
+.Ar address .
 The address can be specified as BD_ADDR or name.
-If given as a name, then the
+If name was specified then
 .Nm
 utility will attempt to resolve the name via
 .Xr bt_gethostbyname 3 .
+.It Fl b
+Detach from the controlling terminal, i.e., run in background.
 .It Fl c Ar channel
-Server mode.
-Specify the RFCOMM channel number to listen on.
+In both client and server mode,
+this option specifies the RFCOMM channel to connect to or listen on.
+In server mode,
+the channel should be a number between 1 and 30.
+If not specified,
 .Nm
-will register the service with the local
-.Xr sdpd 8
-daemon.
-Note that registering services with
-.Xr sdpd 8
-is a privileged operation.
-.It Fl d Ar device
-Use the local device with the specified address.
-The device can be specified by BD_ADDR or device name.
-See
-.Xr btconfig 8
-for a list of available devices.
-If no
-.Ar device
-is specified, the connection will be set up on a system determined device.
-.It Fl m Ar mode
-Set connection link mode.
-Supported modes are:
-.Pp
-.Bl -tag -compact -offset indent -width "encrypt"
-.It auth
-require devices be paired.
-.It encrypt
-auth, plus enable encryption.
-.It secure
-encryption, plus change of link key.
-.El
-.It Fl s Ar service
-This is the service class that will be searched for on the remote device.
-If no
-.Ar service
-is given, the default
-.Qq Serial Port
-service class will be used.
-Known service classes are:
-.Pp
-.Bl -tag -compact -offset indent -width "DUN"
-.It DUN
-Dialup Networking
-.It LAN
-LAN access using PPP
-.It SP
-Serial Port
-.El
-.Pp
-In client mode, the service class may be given as a channel number, for instances
-where the remote device does not provide Service Discovery.
+will try to bind to
+.Dq wildcard
+RFCOMM channel number.
+The actual RFCOMM channel will be obtained via
+.Xr getsockname 2
+call and will be used to register Serial Port service with
+.Xr sdpd 8 .
+In client mode,
+the channel could either be a number between 1 and 30 or a service name.
+Supported service names are:
+.Cm DUN
+(for DialUp Networking service),
+.Cm FAX
+(for Fax service),
+.Cm LAN
+(for LAN Access Using PPP service) and
+.Cm SP
+(for Serial Port service).
+If channel was not specified then
+.Nm
+utility will try to obtain RFCOMM channel for Serial Port service via Service
+Discovery Protocol from the server.
+.It Fl h
+Display usage message and exit.
+.It Fl S
+Server mode; see
+.Sx DESCRIPTION .
 .It Fl t Ar tty
 Slave pseudo tty name.
-If this option is given,
-.Nm
-will detach from the controlling process after the bluetooth connection is
-made, and operate over the named
-.Xr pty 4
-pair.
-Otherwise, stdin/stdout will be used.
+If not set stdin/stdout will be used.
+This option is required if
+.Fl b
+option was specified.
 .El
 .Sh FILES
 .Bl -tag -width ".Pa /dev/tty[p-sP-S][0-9a-v]" -compact
@@ -169,41 +163,24 @@ slave pseudo terminals
 .Sh EXIT STATUS
 .Ex -std
 .Sh EXAMPLES
-.Dl rfcomm_sppd -a 00:01:02:03:04:05 -s 1 -t /dev/ttyp1
+.Dl "rfcomm_sppd -a 00:01:02:03:04:05 -c 1 -t /dev/ttyp1"
 .Pp
-Will open an RFCOMM connection to the server at
+Will start the
+.Nm
+utility and open RFCOMM connection to the server at
 .Li 00:01:02:03:04:05
-on channel
+and channel
 .Li 1 .
 Once the connection has been established,
-.Nm
-will detach and
 .Pa /dev/ttyp1
-can be used to communicate with the remote serial port on the
-server, e.g. with the use of
-.Pp
-.Dl cu -l /dev/ttyp1
+can be used to talk to the remote serial port on the server.
 .Sh SEE ALSO
 .Xr bluetooth 3 ,
-.Xr bluetooth 4 ,
+.Xr ng_btsocket 4 ,
 .Xr pty 4 ,
-.Xr btconfig 8 ,
+.Xr rfcomm_pppd 8 ,
 .Xr sdpd 8
-.Sh HISTORY
-The
-.Nm
-program first appeared in
-.Fx
-and was ported to
-.Nx 4.0
-by
-.An Iain Hibbert
-under the sponsorship of
-.An Itronix, Inc .
 .Sh AUTHORS
-.An -nosplit
 .An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
-and
-.An Iain Hibbert .
 .Sh BUGS
 Please report if found.
diff --git a/usr.bin/rfcomm_sppd/rfcomm_sppd.c b/usr.bin/rfcomm_sppd/rfcomm_sppd.c
index 72b02f4e3b..b26880594f 100644
--- a/usr.bin/rfcomm_sppd/rfcomm_sppd.c
+++ b/usr.bin/rfcomm_sppd/rfcomm_sppd.c
@@ -1,37 +1,8 @@
-/* $NetBSD: rfcomm_sppd.c,v 1.8 2007/04/21 10:39:30 dsl Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
 /*
  * rfcomm_sppd.c
- *
- * Copyright (c) 2007 Iain Hibbert
+ */
+
+/*-
  * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
  * All rights reserved.
  *
@@ -55,8 +26,12 @@
  * 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.
+ *
+ * $Id: rfcomm_sppd.c,v 1.4 2003/09/07 18:15:55 max Exp $
+ * $FreeBSD: head/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sppd.c 188130 2009-02-04 22:04:06Z emax $
  */
 
+#include <sys/stat.h>
 #include <bluetooth.h>
 #include <ctype.h>
 #include <err.h>
@@ -74,109 +49,85 @@
 #include <syslog.h>
 #include <termios.h>
 #include <unistd.h>
-#include <sys/stat.h>
 
-#include <netbt/rfcomm.h>
-
-#include "rfcomm_sdp.h"
-
-#define max(a, b)	((a) > (b) ? (a) : (b))
-
-int open_tty(const char *);
-int open_client(bdaddr_t *, bdaddr_t *, int, const char *);
-int open_server(bdaddr_t *, uint8_t, int, const char *);
-void copy_data(int, int);
-void sighandler(int);
-void usage(void) __dead2;
-void reset_tio(void);
-
-int done;		/* got a signal */
-struct termios tio;	/* stored termios for reset on exit */
-
-struct service {
-	const char	*name;
-	const char	*description;
-	uint16_t	class;
-	int		pdulen;
-} services[] = {
-	{ "DUN",	"Dialup Networking",
-	  SDP_SERVICE_CLASS_DIALUP_NETWORKING,
-	  sizeof(struct sdp_dun_profile)
-	},
-	{ "LAN",	"Lan access using PPP",
-	  SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
-	  sizeof(struct sdp_lan_profile)
-	},
-	{ "SP",		"Serial Port",
-	  SDP_SERVICE_CLASS_SERIAL_PORT,
-	  sizeof(struct sdp_sp_profile)
-	},
-	{ NULL,		NULL,
-	  0,
-	  0
-	}
-};
+#define SPPD_IDENT		"rfcomm_sppd"
+#define SPPD_BUFFER_SIZE	1024
+#define max(a, b)		(((a) > (b))? (a) : (b))
+
+int		rfcomm_channel_lookup	(bdaddr_t const *local,
+					 bdaddr_t const *remote, 
+					 int service, int *channel, int *error);
+
+static int	sppd_ttys_open	(char const *tty, int *amaster, int *aslave);
+static int	sppd_read	(int fd, char *buffer, int size);
+static int	sppd_write	(int fd, char *buffer, int size);
+static void	sppd_sighandler	(int s);
+static void	usage		(void) __dead2;
+
+static int	done;	/* are we done? */
 
+/* Main */
 int
-main(int argc, char *argv[])
+main(int argc, char *argv[]) 
 {
-	struct termios		t;
-	bdaddr_t		laddr, raddr;
-	fd_set			rdset;
-	const char		*service;
-	char			*ep, *tty;
-	int			lm, n, rfcomm, tty_in, tty_out;
-	uint8_t			channel;
-
-	bdaddr_copy(&laddr, BDADDR_ANY);
-	bdaddr_copy(&raddr, BDADDR_ANY);
-	service = "SP";
-	tty = NULL;
-	channel = 0;
-	lm = 0;
+	struct sigaction	 sa;
+	struct sockaddr_rfcomm	 ra;
+	bdaddr_t		 addr;
+	int			 n, background, channel, service,
+				 s, amaster, aslave, fd, doserver;
+	fd_set			 rfd;
+	char			*tty = NULL, *ep = NULL, buf[SPPD_BUFFER_SIZE];
+
+	memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));
+	background = channel = 0;
+	service = SDP_SERVICE_CLASS_SERIAL_PORT;
+	doserver = 0;
 
 	/* Parse command line options */
-	while ((n = getopt(argc, argv, "a:c:d:hm:s:t:")) != -1) {
-		switch (n) {
-		case 'a': /* remote device address */
-			if (!bt_aton(optarg, &raddr)) {
+	while ((n = getopt(argc, argv, "a:bc:t:hS")) != -1) {
+		switch (n) { 
+		case 'a': /* BDADDR */
+			if (!bt_aton(optarg, &addr)) {
 				struct hostent	*he = NULL;
 
 				if ((he = bt_gethostbyname(optarg)) == NULL)
-					errx(EXIT_FAILURE, "%s: %s", optarg,
-					    hstrerror(h_errno));
+					errx(1, "%s: %s", optarg, hstrerror(h_errno));
 
-				bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr);
+				memcpy(&addr, he->h_addr, sizeof(addr));
 			}
 			break;
 
 		case 'c': /* RFCOMM channel */
 			channel = strtoul(optarg, &ep, 10);
-			if (*ep != '\0' || channel < 1 || channel > 30)
-				errx(EXIT_FAILURE, "Invalid channel: %s", optarg);
-
-			break;
-
-		case 'd': /* local device address */
-			if (!bt_devaddr(optarg, &laddr))
-				err(EXIT_FAILURE, "%s", optarg);
-
-			break;
-
-		case 'm': /* Link Mode */
-			if (strcasecmp(optarg, "auth") == 0)
-				lm = RFCOMM_LM_AUTH;
-			else if (strcasecmp(optarg, "encrypt") == 0)
-				lm = RFCOMM_LM_ENCRYPT;
-			else if (strcasecmp(optarg, "secure") == 0)
-				lm = RFCOMM_LM_SECURE;
-			else
-				errx(EXIT_FAILURE, "%s: unknown mode", optarg);
-
+			if (*ep != '\0') {
+				channel = 0;
+				switch (tolower(optarg[0])) {
+				case 'd': /* DialUp Networking */
+					service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
+					break;
+
+				case 'f': /* Fax */
+					service = SDP_SERVICE_CLASS_FAX;
+					break;
+
+				case 'l': /* LAN */
+					service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
+					break;
+
+				case 's': /* Serial Port */
+					service = SDP_SERVICE_CLASS_SERIAL_PORT;
+					break;
+
+				default:
+					errx(1, "Unknown service name: %s",
+						optarg);
+					/* NOT REACHED */
+				}
+			}
 			break;
 
-		case 's': /* service class */
-			service = optarg;
+		case 'b': /* Run in background */
+			background = 1;
 			break;
 
 		case 't': /* Slave TTY name */
@@ -184,7 +135,10 @@ main(int argc, char *argv[])
 				asprintf(&tty, "%s%s", _PATH_DEV, optarg);
 			else
 				tty = optarg;
+			break;
 
+		case 'S':
+			doserver = 1;
 			break;
 
 		case 'h':
@@ -194,117 +148,253 @@ main(int argc, char *argv[])
 		}
 	}
 
-	/*
-	 * validate options:
-	 *	must have channel or remote address but not both
-	 */
-	if ((channel == 0 && bdaddr_any(&raddr))
-	    || (channel != 0 && !bdaddr_any(&raddr)))
+	/* Check if we have everything we need */
+	if (!doserver && memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)
 		usage();
+		/* NOT REACHED */
 
-	/*
-	 * grab ttys before we start the bluetooth
-	 */
-	if (tty == NULL) {
-		tty_in = STDIN_FILENO;
-		tty_out = STDOUT_FILENO;
-	} else {
-		tty_in = open_tty(tty);
-		tty_out = tty_in;
-	}
+	/* Set signal handlers */
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = sppd_sighandler;
 
-	/* open RFCOMM */
-	if (channel == 0)
-		rfcomm = open_client(&laddr, &raddr, lm, service);
-	else
-		rfcomm = open_server(&laddr, channel, lm, service);
+	if (sigaction(SIGTERM, &sa, NULL) < 0)
+		err(1, "Could not sigaction(SIGTERM)");
+ 
+	if (sigaction(SIGHUP, &sa, NULL) < 0)
+		err(1, "Could not sigaction(SIGHUP)");
+ 
+	if (sigaction(SIGINT, &sa, NULL) < 0)
+		err(1, "Could not sigaction(SIGINT)");
 
-	/*
-	 * now we are ready to go, so either detach or maybe turn
-	 * off some input processing, so that rfcomm_sppd can
-	 * be used directly with stdio
-	 */
-	if (tty == NULL) {
-		if (tcgetattr(tty_in, &t) < 0)
-			err(EXIT_FAILURE, "tcgetattr");
+	sa.sa_handler = SIG_IGN;
+	sa.sa_flags = SA_NOCLDWAIT;
+
+	if (sigaction(SIGCHLD, &sa, NULL) < 0)
+		err(1, "Could not sigaction(SIGCHLD)");
 
-		memcpy(&tio, &t, sizeof(tio));
-		t.c_lflag &= ~(ECHO | ICANON);
-		t.c_iflag &= ~(ICRNL);
+	/* Open TTYs */
+	if (tty == NULL) {
+		if (background)
+			usage();
 
-		if (memcmp(&tio, &t, sizeof(tio))) {
-			if (tcsetattr(tty_in, TCSANOW, &t) < 0)
-				err(EXIT_FAILURE, "tcsetattr");
+		amaster = STDIN_FILENO;
+		fd = STDOUT_FILENO;
+	} else {
+		if (sppd_ttys_open(tty, &amaster, &aslave) < 0)
+			exit(1);
+		
+		fd = amaster;
+	}		
+
+	/* Open RFCOMM connection */
+
+	if (doserver) {
+		struct sockaddr_rfcomm	 ma;
+		bdaddr_t		 bt_addr_any;
+		sdp_sp_profile_t	 sp;
+		void			*ss;
+		uint32_t		 sdp_handle;
+		int			 acceptsock, aaddrlen;
+
+		acceptsock = socket(PF_BLUETOOTH, SOCK_STREAM,
+					BLUETOOTH_PROTO_RFCOMM);
+		if (acceptsock < 0)
+			err(1, "Could not create socket");
+
+		memcpy(&bt_addr_any, NG_HCI_BDADDR_ANY, sizeof(bt_addr_any));
+
+		memset(&ma, 0, sizeof(ma));
+		ma.rfcomm_len = sizeof(ma);
+		ma.rfcomm_family = AF_BLUETOOTH;
+		memcpy(&ma.rfcomm_bdaddr, &bt_addr_any, sizeof(bt_addr_any));
+		ma.rfcomm_channel = channel;
+
+		if (bind(acceptsock, (struct sockaddr *)&ma, sizeof(ma)) < 0)
+			err(1, "Could not bind socket on channel %d", channel);
+		if (listen(acceptsock, 10) != 0)
+			err(1, "Could not listen on socket");
+
+		aaddrlen = sizeof(ma);
+		if (getsockname(acceptsock, (struct sockaddr *)&ma, &aaddrlen) < 0)
+			err(1, "Could not get socket name");
+		channel = ma.rfcomm_channel;
+
+		ss = sdp_open_local(NULL);
+		if (ss == NULL)
+			errx(1, "Unable to create local SDP session");
+		if (sdp_error(ss) != 0)
+			errx(1, "Unable to open local SDP session. %s (%d)",
+			    strerror(sdp_error(ss)), sdp_error(ss));
+		memset(&sp, 0, sizeof(sp));
+		sp.server_channel = channel;
+
+		if (sdp_register_service(ss, SDP_SERVICE_CLASS_SERIAL_PORT,
+				&bt_addr_any, (void *)&sp, sizeof(sp),
+				&sdp_handle) != 0) {
+			errx(1, "Unable to register LAN service with "
+			    "local SDP daemon. %s (%d)",
+			    strerror(sdp_error(ss)), sdp_error(ss));
+		}
 
-			atexit(reset_tio);
+		s = -1;
+		while (s < 0) {
+			aaddrlen = sizeof(ra);
+			s = accept(acceptsock, (struct sockaddr *)&ra,
+			    &aaddrlen);
+			if (s < 0)
+				err(1, "Unable to accept()");
+			if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) &&
+			    memcmp(&addr, &ra.rfcomm_bdaddr, sizeof(addr))) {
+				warnx("Connect from wrong client");
+				close(s);
+				s = -1;
+			}
 		}
+		sdp_unregister_service(ss, sdp_handle);
+		sdp_close(ss);
+		close(acceptsock);
 	} else {
-		if (daemon(0, 0) < 0)
-			err(EXIT_FAILURE, "daemon() failed");
+		/* Check channel, if was not set then obtain it via SDP */
+		if (channel == 0 && service != 0)
+			if (rfcomm_channel_lookup(NULL, &addr,
+				    service, &channel, &n) != 0)
+				errc(1, n, "Could not obtain RFCOMM channel");
+		if (channel <= 0 || channel > 30)
+			errx(1, "Invalid RFCOMM channel number %d", channel);
+
+		s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
+		if (s < 0)
+			err(1, "Could not create socket");
+
+		memset(&ra, 0, sizeof(ra));
+		ra.rfcomm_len = sizeof(ra);
+		ra.rfcomm_family = AF_BLUETOOTH;
+
+		if (bind(s, (struct sockaddr *) &ra, sizeof(ra)) < 0)
+			err(1, "Could not bind socket");
+
+		memcpy(&ra.rfcomm_bdaddr, &addr, sizeof(ra.rfcomm_bdaddr));
+		ra.rfcomm_channel = channel;
+
+		if (connect(s, (struct sockaddr *) &ra, sizeof(ra)) < 0)
+			err(1, "Could not connect socket");
 	}
 
-	/* catch signals */
-	done = 0;
-	(void)signal(SIGHUP, sighandler);
-	(void)signal(SIGINT, sighandler);
-	(void)signal(SIGPIPE, sighandler);
-	(void)signal(SIGTERM, sighandler);
+	/* Became daemon if required */
+	if (background && daemon(0, 0) < 0)
+		err(1, "Could not daemon()");
 
-	openlog(getprogname(), LOG_PERROR | LOG_PID, LOG_DAEMON);
-	syslog(LOG_INFO, "Starting on %s...", (tty ? tty : "stdio"));
+	openlog(SPPD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON);
+	syslog(LOG_INFO, "Starting on %s...", (tty != NULL)? tty : "stdin/stdout");
 
-	n = max(tty_in, rfcomm) + 1;
-	while (!done) {
-		FD_ZERO(&rdset);
-		FD_SET(tty_in, &rdset);
-		FD_SET(rfcomm, &rdset);
+	for (done = 0; !done; ) {
+		FD_ZERO(&rfd);
+		FD_SET(amaster, &rfd);
+		FD_SET(s, &rfd);
 
-		if (select(n, &rdset, NULL, NULL, NULL) < 0) {
+		n = select(max(amaster, s) + 1, &rfd, NULL, NULL, NULL);
+		if (n < 0) {
 			if (errno == EINTR)
 				continue;
 
-			syslog(LOG_ERR, "select error: %m");
-			exit(EXIT_FAILURE);
+			syslog(LOG_ERR, "Could not select(). %s",
+					strerror(errno));
+			exit(1);
+		}
+
+		if (n == 0)
+			continue;
+
+		if (FD_ISSET(amaster, &rfd)) {
+			n = sppd_read(amaster, buf, sizeof(buf));
+			if (n < 0) {
+				syslog(LOG_ERR, "Could not read master pty, " \
+					"fd=%d. %s", amaster, strerror(errno));
+				exit(1);
+			}
+
+			if (n == 0)
+				break; /* XXX */
+
+			if (sppd_write(s, buf, n) < 0) {
+				syslog(LOG_ERR, "Could not write to socket, " \
+					"fd=%d, size=%d. %s",
+					s, n, strerror(errno));
+				exit(1);
+			}
 		}
 
-		if (FD_ISSET(tty_in, &rdset))
-			copy_data(tty_in, rfcomm);
+		if (FD_ISSET(s, &rfd)) {
+			n = sppd_read(s, buf, sizeof(buf));
+			if (n < 0) {
+				syslog(LOG_ERR, "Could not read socket, " \
+					"fd=%d. %s", s, strerror(errno));
+				exit(1);
+			}
+
+			if (n == 0)
+				break;
 
-		if (FD_ISSET(rfcomm, &rdset))
-			copy_data(rfcomm, tty_out);
+			if (sppd_write(fd, buf, n) < 0) {
+				syslog(LOG_ERR, "Could not write to master " \
+					"pty, fd=%d, size=%d. %s",
+					fd, n, strerror(errno));
+				exit(1);
+			}
+		}
 	}
 
-	syslog(LOG_INFO, "Completed on %s", (tty ? tty : "stdio"));
-	exit(EXIT_SUCCESS);
+	syslog(LOG_INFO, "Completed on %s", (tty != NULL)? tty : "stdin/stdout");
+	closelog();
+
+	close(s);
+
+	if (tty != NULL) {
+		close(aslave);
+		close(amaster);
+	}	
+
+	return (0);
 }
 
-int
-open_tty(const char *tty)
+/* Open TTYs */
+static int
+sppd_ttys_open(char const *tty, int *amaster, int *aslave)
 {
 	char		 pty[PATH_MAX], *slash;
 	struct group	*gr = NULL;
 	gid_t		 ttygid;
-	int		 master;
+	struct termios	 tio;
 
 	/*
 	 * Construct master PTY name. The slave tty name must be less then
-	 * PATH_MAX characters in length, must contain '/' character and
+	 * PATH_MAX characters in length, must contain '/' character and 
 	 * must not end with '/'.
 	 */
-	if (strlen(tty) >= sizeof(pty))
-		errx(EXIT_FAILURE, ": tty name too long");
+
+	if (strlen(tty) >= sizeof(pty)) {
+		syslog(LOG_ERR, "Slave tty name is too long");
+		return (-1);
+	}
 
 	strlcpy(pty, tty, sizeof(pty));
 	slash = strrchr(pty, '/');
-	if (slash == NULL || slash[1] == '\0')
-		errx(EXIT_FAILURE, "%s: invalid tty", tty);
+	if (slash == NULL || slash[1] == '\0') {
+		syslog(LOG_ERR, "Invalid slave tty name (%s)", tty);
+		return (-1);
+	}
 
 	slash[1] = 'p';
-	if (strcmp(pty, tty) == 0)
-		errx(EXIT_FAILURE, "Master and slave tty are the same (%s)", tty);
+	
+	if (strcmp(pty, tty) == 0) {
+		syslog(LOG_ERR, "Master and slave tty are the same (%s)", tty);
+		return (-1);
+	}
 
-	if ((master = open(pty, O_RDWR, 0)) < 0)
-		err(EXIT_FAILURE, "%s", pty);
+	if ((*amaster = open(pty, O_RDWR, 0)) < 0) {
+		syslog(LOG_ERR, "Could not open(%s). %s", pty, strerror(errno));
+		return (-1);
+	}
 
 	/*
 	 * Slave TTY
@@ -313,207 +403,102 @@ open_tty(const char *tty)
 	if ((gr = getgrnam("tty")) != NULL)
 		ttygid = gr->gr_gid;
 	else
-		ttygid = (gid_t)-1;
-
-	(void)chown(tty, getuid(), ttygid);
-	(void)chmod(tty, S_IRUSR | S_IWUSR | S_IWGRP);
-	(void)revoke(tty);
-
-	return master;
-}
-
-int
-open_client(bdaddr_t *laddr, bdaddr_t *raddr, int lm, const char *service)
-{
-	struct sockaddr_bt sa;
-	struct service *s;
-	struct linger l;
-	char *ep;
-	int fd;
-	uint8_t channel = 0;	/* avoid gcc warnings */
-
-	for (s = services ; ; s++) {
-		if (s->name == NULL) {
-			channel = strtoul(service, &ep, 10);
-			if (*ep != '\0' || channel < 1 || channel > 30)
-				errx(EXIT_FAILURE, "Invalid service: %s", service);
-
-			break;
-		}
+		ttygid = -1;
 
-		if (strcasecmp(s->name, service) == 0) {
-			if (rfcomm_channel_lookup(laddr, raddr, s->class, &channel, &errno) < 0)
-				err(EXIT_FAILURE, "%s", s->name);
+	(void) chown(tty, getuid(), ttygid);
+	(void) chmod(tty, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+	(void) revoke(tty);
 
-			break;
-		}
+	if ((*aslave = open(tty, O_RDWR, 0)) < 0) {
+		syslog(LOG_ERR, "Could not open(%s). %s", tty, strerror(errno));
+		close(*amaster);
+		return (-1);
 	}
 
-	memset(&sa, 0, sizeof(sa));
-	sa.bt_len = sizeof(sa);
-	sa.bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&sa.bt_bdaddr, laddr);
-
-	fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-	if (fd < 0)
-		err(EXIT_FAILURE, "socket()");
-
-	if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
-		err(EXIT_FAILURE, "bind(%s)", bt_ntoa(laddr, NULL));
-
-	memset(&l, 0, sizeof(l));
-	l.l_onoff = 1;
-	l.l_linger = 5;
-	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
-		err(EXIT_FAILURE, "linger()");
-
-	if (setsockopt(fd, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
-		err(EXIT_FAILURE, "link mode");
-
-	sa.bt_channel = channel;
-	bdaddr_copy(&sa.bt_bdaddr, raddr);
+	/*
+	 * Make slave TTY raw
+	 */
 
-	if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
-		err(EXIT_FAILURE, "connect(%s, %d)", bt_ntoa(raddr, NULL),
-						     channel);
+	cfmakeraw(&tio);
 
-	return fd;
-}
+	if (tcsetattr(*aslave, TCSANOW, &tio) < 0) {
+		syslog(LOG_ERR, "Could not tcsetattr(). %s", strerror(errno));
+		close(*aslave);
+		close(*amaster);
+		return (-1);
+	}
 
-/*
- * In all the profiles we currently support registering, the channel
- * is the first octet in the PDU, and it seems all the rest can be
- * zero, so we just use an array of uint8_t big enough to store the
- * largest, currently LAN. See <sdp.h> for definitions..
- */
-#define pdu_len		sizeof(struct sdp_lan_profile)
+	return (0);
+} /* sppd_ttys_open */
 
-int
-open_server(bdaddr_t *laddr, uint8_t channel, int lm, const char *service)
+/* Read data */
+static int
+sppd_read(int fd, char *buffer, int size)
 {
-	struct sockaddr_bt sa;
-	struct linger l;
-	socklen_t len;
-	void *ss;
-	int sv, fd, n;
-	uint8_t pdu[pdu_len];
-
-	memset(&sa, 0, sizeof(sa));
-	sa.bt_len = sizeof(sa);
-	sa.bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&sa.bt_bdaddr, laddr);
-	sa.bt_channel = channel;
-
-	sv = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-	if (sv < 0)
-		err(EXIT_FAILURE, "socket()");
-
-	if (bind(sv, (struct sockaddr *)&sa, sizeof(sa)) < 0)
-		err(EXIT_FAILURE, "bind(%s, %d)", bt_ntoa(laddr, NULL),
-						  channel);
-
-	if (setsockopt(sv, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
-		err(EXIT_FAILURE, "link mode");
-
-	if (listen(sv, 1) < 0)
-		err(EXIT_FAILURE, "listen()");
-
-	/* Register service with SDP server */
-	for (n = 0 ; ; n++) {
-		if (services[n].name == NULL)
-			usage();
-
-		if (strcasecmp(services[n].name, service) == 0)
-			break;
-	}
+	int	n;
 
-	memset(pdu, 0, pdu_len);
-	pdu[0] = channel;
+again:
+	n = read(fd, buffer, size);
+	if (n < 0) {
+		if (errno == EINTR)
+			goto again;
 
-	ss = sdp_open_local(NULL);
-	if (ss == NULL || (errno = sdp_error(ss)) != 0)
-		err(EXIT_FAILURE, "sdp_open_local");
-
-	if (sdp_register_service(ss, services[n].class, laddr,
-		    pdu, services[n].pdulen, NULL) != 0) {
-		errno = sdp_error(ss);
-		err(EXIT_FAILURE, "sdp_register_service");
+		return (-1);
 	}
 
-	len = sizeof(sa);
-	fd = accept(sv, (struct sockaddr *)&sa, &len);
-	if (fd < 0)
-		err(EXIT_FAILURE, "accept");
-
-	memset(&l, 0, sizeof(l));
-	l.l_onoff = 1;
-	l.l_linger = 5;
-	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
-		err(EXIT_FAILURE, "linger()");
-
-	close(sv);
-	return fd;
-}
+	return (n);
+} /* sppd_read */
 
-void
-copy_data(int src, int dst)
+/* Write data */
+static int
+sppd_write(int fd, char *buffer, int size)
 {
-	static char	buf[BUFSIZ];
-	ssize_t		nr, nw, off;
+	int	n, wrote;
 
-	while ((nr = read(src, buf, sizeof(buf))) == -1) {
-		if (errno != EINTR) {
-			syslog(LOG_ERR, "read failed: %m");
-			exit(EXIT_FAILURE);
-		}
-	}
+	for (wrote = 0; size > 0; ) {
+		n = write(fd, buffer, size);
+		switch (n) {
+		case -1:
+			if (errno != EINTR)
+				return (-1);
+			break;
 
-	if (nr == 0)	/* reached EOF */
-		done++;
+		case 0: 
+			/* XXX can happen? */
+			break;
 
-	for (off = 0 ; nr ; nr -= nw, off += nw) {
-		if ((nw = write(dst, buf + off, (size_t)nr)) == -1) {
-			syslog(LOG_ERR, "write failed: %m");
-			exit(EXIT_FAILURE);
+		default:
+			wrote += n;
+			buffer += n;
+			size -= n;
+			break;
 		}
 	}
-}
 
-void
-sighandler(int s __unused)
-{
-
-	done++;
-}
+	return (wrote);
+} /* sppd_write */
 
-void
-reset_tio(void)
+/* Signal handler */
+static void
+sppd_sighandler(int s)
 {
-
-	tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
-}
-
-void
+	syslog(LOG_INFO, "Signal %d received. Total %d signals received\n",
+			s, ++ done);
+} /* sppd_sighandler */
+ 
+/* Display usage and exit */
+static void
 usage(void)
 {
-	const char *cmd = getprogname();
-	struct service *s;
-
-	fprintf(stderr, "Usage: %s [-d device] [-m mode] [-s service] [-t tty]\n"
-			"       %*s {-a bdaddr | -c channel}\n"
-			"\n"
-			"Where:\n"
-			"\t-a bdaddr    remote device address\n"
-			"\t-c channel   local RFCOMM channel\n"
-			"\t-d device    local device address\n"
-			"\t-m mode      link mode\n"
-			"\t-s service   service class\n"
-			"\t-t tty       run in background using pty\n"
-			"\n", cmd, (int)strlen(cmd), "");
-
-	fprintf(stderr, "Known service classes:\n");
-	for (s = services ; s->name != NULL ; s++)
-		fprintf(stderr, "\t%-13s%s\n", s->name, s->description);
-
-	exit(EXIT_FAILURE);
-}
+	fprintf(stdout,
+"Usage: %s options\n" \
+"Where options are:\n" \
+"\t-a address Peer address (required in client mode)\n" \
+"\t-b         Run in background\n" \
+"\t-c channel RFCOMM channel to connect to or listen on\n" \
+"\t-t tty     TTY name (required in background mode)\n" \
+"\t-S         Server mode\n" \
+"\t-h         Display this message\n", SPPD_IDENT);
+	exit(255);
+} /* usage */
+
diff --git a/usr.bin/sdpquery/Makefile b/usr.bin/sdpquery/Makefile
deleted file mode 100644
index 80eb255a37..0000000000
--- a/usr.bin/sdpquery/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# $NetBSD: Makefile,v 1.3 2007/05/28 12:06:31 tls Exp $
-
-PROG=		sdpquery
-MAN=		sdpquery.1
-SRCS=		sdpquery.c search.c
-
-CFLAGS+=	-I${.CURDIR}/../../sys
-DPADD+=		${LIBBLUETOOTH} ${LIBSDP}
-LDADD+=		-lbluetooth -lsdp
-
-WARNS?=		3
-NO_STRICT_ALIASING=
-
-.include <bsd.prog.mk>
diff --git a/usr.bin/sdpquery/sdpquery.1 b/usr.bin/sdpquery/sdpquery.1
deleted file mode 100644
index 54b8c5f9e1..0000000000
--- a/usr.bin/sdpquery/sdpquery.1
+++ /dev/null
@@ -1,210 +0,0 @@
-.\" $NetBSD: sdpquery.1,v 1.8 2007/02/17 09:39:11 wiz Exp $
-.\"
-.\" Copyright (c) 2006 Itronix Inc.
-.\" 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. The name of Itronix Inc. may not be used to endorse
-.\"    or promote products derived from this software without specific
-.\"    prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
-.\" 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: src/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8,v 1.6 2005/07/09 19:04:43 markus Exp $
-.\"
-.Dd February 17, 2007
-.Dt SDPQUERY 1
-.Os
-.Sh NAME
-.Nm sdpquery
-.Nd SDP query utility
-.Sh SYNOPSIS
-.Nm
-.Fl h
-.Nm
-.Op Fl d Ar device
-.Fl a Ar address
-.Ar command
-.Op Ar parameters ...
-.Nm
-.Op Fl c Ar path
-.Fl l
-.Ar command
-.Op Ar parameters ...
-.Sh DESCRIPTION
-The
-.Nm
-utility attempts to query the specified Service Discovery Protocol
-(SDP) server.
-Remote SDP servers are identified by their address.
-Connection to the local SDP server is made via the control socket.
-The
-.Nm
-utility uses Service Search Attribute Requests and prints results to
-standard output and error messages to standard error.
-.Pp
-The options are as follows:
-.Bl -tag -width ".Fl a Ar address"
-.It Fl a Ar address
-Connect to the remote device with the specified address.
-The address can be specified as BD_ADDR or a name.
-If a name was specified, the
-.Nm
-utility attempts to resolve the name via
-.Xr bt_gethostbyname 3 .
-If no remote address is given,
-.Nm
-attempts to contact a local SDP server via the control socket.
-.It Fl c Ar path
-Specify path to the control socket.
-The default path is
-.Pa /var/run/sdp .
-.It Fl d Ar device
-Connect from the local device with the specified address.
-The device can be specified by BD_ADDR or device name.
-See
-.Xr btconfig 8
-for a list of devices available.
-If no device is specified, the
-.Nm
-utility will use the best available.
-.It Fl l
-Query the local SDP server via the control socket.
-.It Fl h
-Display usage message and exit.
-.El
-.Pp
-The currently supported commands in
-.Nm
-are:
-.Pp
-.Bl -tag -width ".Cm search Ar service" -compact
-.It Cm Browse Op Ar group
-Browse for services.
-The
-.Ar group
-parameter is a 16-bit UUID of the group to browse.
-If omitted, the Public Browse Group. is used.
-.Pp
-.It Cm Search Ar service
-Search for the
-.Ar service .
-The
-.Ar service
-parameter is a 16-bit UUID of the service to search for.
-For the following services it is possible to use service name
-instead of service UUID:
-.Pp
-.Bl -tag -compact -width "OPUSH"
-.It CIP
-Common ISDN Access
-.It CTP
-Cordless Telephony
-.It DUN
-DialUp Networking
-.It FAX
-Fax
-.It FTRN
-OBEX File Transfer
-.It GN
-Group ad-hoc Network
-.It HID
-Human Interface Device
-.It HF
-Handsfree
-.It HSET
-Headset
-.It LAN
-LAN Access Using PPP
-.It NAP
-Network Access Point
-.It OPUSH
-OBEX Object Push
-.It PANU
-Personal Area Networking User
-.It SP
-Serial Port
-.El
-.El
-.Sh EXIT STATUS
-.Ex -std
-.Sh SEE ALSO
-.Xr bluetooth 3 ,
-.Xr sdp 3 ,
-.Xr btconfig 8 ,
-.Xr sdpd 8
-.Sh HISTORY
-The
-.Nm
-command first appeared in
-.Fx 5.3
-as
-.Nm sdpcontrol .
-It was ported to
-.Nx 4.0
-under its present name by
-.An Iain Hibbert
-under the sponsorship of Itronix, Inc and imported into
-.Dx 1.11 .
-.Sh AUTHORS
-.An -nosplit
-.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
-and
-.An Iain Hibbert
-for Itronix, Inc.
-.Sh CAVEATS
-The
-.Nm
-utility only requests the following attributes from the SDP server:
-.Pp
-.Bl -enum -offset indent -compact
-.It
-Service Record Handle
-.It
-Service Class ID List
-.It
-Protocol Descriptor List
-.It
-Bluetooth Profile Descriptor List
-.El
diff --git a/usr.bin/sdpquery/sdpquery.c b/usr.bin/sdpquery/sdpquery.c
deleted file mode 100644
index af59c6ac1d..0000000000
--- a/usr.bin/sdpquery/sdpquery.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/* $NetBSD: sdpquery.c,v 1.3 2007/03/30 21:25:00 plunky Exp $ */
-/* $DragonFly: src/usr.bin/sdpquery/sdpquery.c,v 1.1 2008/02/08 14:06:25 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 <assert.h>
-#include <bluetooth.h>
-#include <err.h>
-#include <errno.h>
-#include <sdp.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "sdpquery.h"
-
-static void usage(void);
-
-const char *control_socket;
-
-static struct command {
-	const char	*command;
-	int		(*handler)(bdaddr_t *, bdaddr_t *, int, char const **);
-	const char	*usage;
-} commands[] = {
-	{ "Browse",	do_sdp_browse,	"[UUID]"	},
-	{ "Search",	do_sdp_search,	"<service>"	},
-	{ NULL,		NULL,		NULL		}
-};
-
-int
-main(int argc, char *argv[])
-{
-	bdaddr_t	laddr, raddr;
-	struct command *cmd;
-	int		ch, local;
-
-	bdaddr_copy(&laddr, BDADDR_ANY);
-	bdaddr_copy(&raddr, BDADDR_ANY);
-	control_socket = NULL;
-	local = 0;
-
-	while ((ch = getopt(argc, argv, "a:c:d:hl")) != -1) {
-		switch (ch) {
-		case 'a': /* remote address */
-			if (!bt_aton(optarg, &raddr)) {
-				struct hostent  *he = NULL;
-
-				if ((he = bt_gethostbyname(optarg)) == NULL)
-					errx(EXIT_FAILURE, "%s: %s",
-						optarg, hstrerror(h_errno));
-
-				bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr);
-			}
-			break;
-
-		case 'c':
-			control_socket = optarg;
-			break;
-
-		case 'd': /* local device address */
-			if (!bt_devaddr(optarg, &laddr))
-				err(EXIT_FAILURE, "%s", optarg);
-
-			break;
-
-		case 'l': /* local sdpd */
-			local = 1;
-			break;
-
-		case 'h':
-		default:
-			usage();
-			/* NOT REACHED */
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-
-	optind = 0;
-	optreset = 1;
-
-	if (argc < 1
-	    || (bdaddr_any(&raddr) && !local)
-	    || (!bdaddr_any(&raddr) && local))
-		usage();
-
-	for (cmd = commands ; cmd->command != NULL; cmd++) {
-		if (strcasecmp(*argv, cmd->command) == 0)
-			return (*cmd->handler)(&laddr, &raddr, --argc, (char const **)++argv);
-	}
-
-	errx(EXIT_FAILURE, "%s: Unknown Command", *argv);
-}
-
-/* Usage */
-static void
-usage(void)
-{
-	struct command *cmd;
-
-	fprintf(stderr,
-		"Usage: %s [-d device] -a bdaddr <command> [parameters..]\n"
-		"       %s [-c path] -l <command> [parameters..]\n"
-		"\n", getprogname(), getprogname());
-
-	fprintf(stderr,
-		"Where:\n"
-		"\t-a bdaddr    remote address\n"
-		"\t-c path      path to control socket\n"
-		"\t-d device    local device address\n"
-		"\t-l           connect to the local SDP server via control socket\n"
-		"\t-h           display usage and quit\n"
-		"\n"
-		"Commands:\n");
-
-	for (cmd = commands ; cmd->command != NULL ; cmd++)
-		fprintf(stderr, "\t%-13s%s\n", cmd->command, cmd->usage);
-
-	exit(EXIT_FAILURE);
-}
diff --git a/usr.bin/sdpquery/sdpquery.h b/usr.bin/sdpquery/sdpquery.h
deleted file mode 100644
index 61e7121b52..0000000000
--- a/usr.bin/sdpquery/sdpquery.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* $NetBSD: sdpquery.h,v 1.2 2006/07/26 10:54:49 tron Exp $ */
-/* $DragonFly: src/usr.bin/sdpquery/sdpquery.h,v 1.1 2008/02/08 14:06:25 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
-
-#ifndef __BTQUERY_H__
-#define __BTQUERY_H__
-
-extern const char *control_socket;
-
-int do_sdp_browse(bdaddr_t *, bdaddr_t *, int, char const **);
-int do_sdp_search(bdaddr_t *, bdaddr_t *, int, char const **);
-
-#endif /* __BTQUERY_H__ */
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index 5c5c7bce00..7a82792185 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -1,5 +1,7 @@
 #	From: @(#)Makefile	5.20 (Berkeley) 6/12/93
 # $FreeBSD: src/usr.sbin/Makefile,v 1.183.2.14 2003/04/16 11:01:51 ru Exp $
+#
+# XXX MISSING: bthidd btpand
 
 .include "../sys/platform/${MACHINE_PLATFORM}/Makefile.inc"
 
@@ -10,12 +12,14 @@ SUBDIR= 802_11 \
 	adduser \
 	arp \
 	asf \
+	ath3kfw \
 	authpf \
 	autofs \
+	bcmfw \
 	boot0cfg \
 	bootparamd \
-	btconfig \
-	bthcid \
+	bt3cfw \
+	bthidcontrol \
 	burncd \
 	cdcontrol \
 	chkgrp \
@@ -42,6 +46,9 @@ SUBDIR= 802_11 \
 	ftp-proxy \
 	fwcontrol \
 	gifconfig \
+	hccontrol \
+	hcsecd \
+	hcseriald \
 	hotplugd \
 	ifmcstat \
 	inetd \
@@ -54,6 +61,8 @@ SUBDIR= 802_11 \
 	kbdmap \
 	keyserv \
 	lastlogin \
+	l2control \
+	l2ping \
 	mailwrapper \
 	makefs \
 	manctl \
@@ -90,6 +99,7 @@ SUBDIR= 802_11 \
 	rarpd \
 	repquota \
 	resident \
+	rfcomm_pppd \
 	rip6query \
 	rmt \
 	route6d \
@@ -107,6 +117,7 @@ SUBDIR= 802_11 \
 	rtsold \
 	rwhod \
 	sa \
+	sdpcontrol \
 	sdpd \
 	sensorsd \
 	service \
diff --git a/usr.sbin/ath3kfw/Makefile b/usr.sbin/ath3kfw/Makefile
new file mode 100644
index 0000000000..c509671c0d
--- /dev/null
+++ b/usr.sbin/ath3kfw/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD: head/usr.sbin/bluetooth/ath3kfw/Makefile 222772 2011-06-06 20:24:17Z ed $
+
+PROG=		ath3kfw
+MAN=		ath3kfw.8
+DPADD+=		${LIBUSB}
+LDADD+=		-lusb
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ath3kfw/ath3kfw.8 b/usr.sbin/ath3kfw/ath3kfw.8
new file mode 100644
index 0000000000..6a190871e6
--- /dev/null
+++ b/usr.sbin/ath3kfw/ath3kfw.8
@@ -0,0 +1,78 @@
+.\" Copyright (c) 2010 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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: head/usr.sbin/bluetooth/ath3kfw/ath3kfw.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd November 9, 2010
+.Dt ATH3KFW 8
+.Os
+.Sh NAME
+.Nm ath3kfw
+.Nd firmware download utility for Atheros AR3011 chip based Bluetooth USB devices
+.Sh SYNOPSIS
+.Nm
+.Fl d Ar device_name
+.Fl f Ar firmware_file_name
+.Nm
+.Fl h
+.Sh DESCRIPTION
+The
+.Nm
+utility downloads the specified firmware file to the specified
+.Xr ugen 4
+device.
+.Pp
+This utility will
+.Em only
+work with Atheros AR3011 chip based Bluetooth USB devices.
+The identification is currently based on USB vendor ID/product ID pair.
+The vendor ID should be 0x0cf3
+.Pq Dv USB_VENDOR_ATHEROS2
+and the product ID should be 0x3000.
+.Pp
+Firmware files ath3k-1.fw and ath3k-2.fw can be obtained from the
+linux-firmware RPM.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl d Ar device_name
+Specify
+.Xr ugen 4
+device name.
+.It Fl f Ar firmware_file_name
+Specify firmware file name for download.
+.It Fl h
+Display usage message and exit.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr libusb 3 ,
+.Xr ugen 4 ,
+.Xr devd 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report if found.
diff --git a/usr.sbin/ath3kfw/ath3kfw.c b/usr.sbin/ath3kfw/ath3kfw.c
new file mode 100644
index 0000000000..9e1d5fd755
--- /dev/null
+++ b/usr.sbin/ath3kfw/ath3kfw.c
@@ -0,0 +1,297 @@
+/*
+ * ath3kfw.c
+ */
+
+/*-
+ * Copyright (c) 2010 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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: head/usr.sbin/bluetooth/ath3kfw/ath3kfw.c 249179 2013-04-05 23:42:22Z adrian $
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libusb20_desc.h>
+#include <libusb20.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define ATH3KFW			"ath3kfw"
+#define ATH3KFW_VENDOR_ID	0x0cf3
+#define ATH3KFW_PRODUCT_ID	0x3000
+#define ATH3KFW_FW		"/usr/local/etc/ath3k-1.fw"
+#define ATH3KFW_BULK_EP		0x02
+#define	ATH3KFW_REQ_DFU_DNLOAD	1
+#define	ATH3KFW_MAX_BSIZE	4096
+
+static int	parse_ugen_name		(char const *ugen, uint8_t *bus,
+					 uint8_t *addr);
+static int	find_device		(struct libusb20_backend *be,
+					 uint8_t bus, uint8_t addr,
+					 struct libusb20_device **dev);
+static int	download_firmware	(struct libusb20_device *dev,
+					 char const *firmware);
+static void	usage			(void);
+
+static int			vendor_id = ATH3KFW_VENDOR_ID;
+static int			product_id = ATH3KFW_PRODUCT_ID;
+
+/*
+ * Firmware downloader for Atheros AR3011 based USB Bluetooth devices
+ */
+
+int
+main(int argc, char **argv)
+{
+	uint8_t			bus, addr;
+	char const		*firmware;
+	struct libusb20_backend	*be;
+	struct libusb20_device	*dev;
+	int			n;
+
+	openlog(ATH3KFW, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_USER);
+
+	bus = 0;
+	addr = 0;
+	firmware = ATH3KFW_FW;
+
+	while ((n = getopt(argc, argv, "d:f:hp:v:")) != -1) {
+		switch (n) {
+		case 'd': /* ugen device name */
+			if (parse_ugen_name(optarg, &bus, &addr) < 0)
+				usage();
+			break;
+
+		case 'f': /* firmware file */
+			firmware = optarg;
+			break;
+		case 'p': /* product id */
+			product_id = strtol(optarg, NULL, 0);
+			break;
+		case 'v': /* vendor id */
+			vendor_id = strtol(optarg, NULL, 0);
+			break;
+		case 'h':
+		default:
+			usage();
+			break;
+			/* NOT REACHED */
+		}
+	}
+
+	be = libusb20_be_alloc_default();
+	if (be == NULL) {
+		syslog(LOG_ERR, "libusb20_be_alloc_default() failed");
+		return (-1);
+	}
+
+	if (find_device(be, bus, addr, &dev) < 0) {
+		syslog(LOG_ERR, "ugen%d.%d is not recognized as " \
+			"Atheros AR3011 based device " \
+			"(possibly caused by lack of permissions)", bus, addr);
+		return (-1);
+	}
+
+	if (download_firmware(dev, firmware) < 0) {
+		syslog(LOG_ERR, "could not download %s firmare to ugen%d.%d",
+			firmware, bus, addr);
+		return (-1);
+	}
+
+	libusb20_be_free(be);
+	closelog();
+	
+	return (0);
+}
+
+/*
+ * Parse ugen name and extract device's bus and address
+ */
+
+static int
+parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
+{
+	char	*ep;
+
+	if (strncmp(ugen, "ugen", 4) != 0)
+		return (-1);
+
+	*bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
+	if (*ep != '.')
+		return (-1);
+
+	*addr = (uint8_t) strtoul(ep + 1, &ep, 10);
+	if (*ep != '\0')
+		return (-1);
+
+	return (0);
+}
+
+/*
+ * Find USB device
+ */
+
+static int
+find_device(struct libusb20_backend *be, uint8_t bus, uint8_t addr,
+		struct libusb20_device **dev)
+{
+	struct LIBUSB20_DEVICE_DESC_DECODED	*desc;
+
+	*dev = NULL;
+
+	while ((*dev = libusb20_be_device_foreach(be, *dev)) != NULL) {
+		if (libusb20_dev_get_bus_number(*dev) != bus ||
+		    libusb20_dev_get_address(*dev) != addr)
+			continue;
+
+		desc = libusb20_dev_get_device_desc(*dev);
+		if (desc == NULL)
+			continue;
+
+		if (desc->idVendor != vendor_id ||
+		    desc->idProduct != product_id)
+			continue;
+
+		break;
+	}
+
+	return ((*dev == NULL)? -1 : 0);
+}
+
+/*
+ * Download firmware
+ */
+
+static int
+download_firmware(struct libusb20_device *dev, char const *firmware)
+{
+	struct libusb20_transfer		*bulk;
+	struct LIBUSB20_CONTROL_SETUP_DECODED	req;
+	int					fd, n, error;
+	uint8_t					buf[ATH3KFW_MAX_BSIZE];
+
+	error = -1;
+
+	if (libusb20_dev_open(dev, 1) != 0) {
+		syslog(LOG_ERR, "libusb20_dev_open() failed");
+		return (error);
+	}
+
+	if ((bulk = libusb20_tr_get_pointer(dev, 0)) == NULL) {
+		syslog(LOG_ERR, "libusb20_tr_get_pointer() failed");
+		goto out;
+	}
+
+	if (libusb20_tr_open(bulk, ATH3KFW_MAX_BSIZE, 1, ATH3KFW_BULK_EP) != 0) {
+		syslog(LOG_ERR, "libusb20_tr_open(%d, 1, %d) failed",
+			ATH3KFW_MAX_BSIZE, ATH3KFW_BULK_EP);
+		goto out;
+	}
+
+	if ((fd = open(firmware, O_RDONLY)) < 0) {
+		syslog(LOG_ERR, "open(%s) failed. %s",
+			firmware, strerror(errno));
+		goto out1;
+	}
+
+	n = read(fd, buf, 20);
+	if (n != 20) {
+		syslog(LOG_ERR, "read(%s, 20) failed. %s",
+			firmware, strerror(errno));
+		goto out2;
+	}
+
+	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
+	req.bmRequestType = LIBUSB20_REQUEST_TYPE_VENDOR;
+	req.bRequest = ATH3KFW_REQ_DFU_DNLOAD;
+	req.wLength = 20;
+
+	if (libusb20_dev_request_sync(dev, &req, buf, NULL, 5000, 0) != 0) {
+		syslog(LOG_ERR, "libusb20_dev_request_sync() failed");
+		goto out2;
+	}
+
+	for (;;) {
+		n = read(fd, buf, sizeof(buf));
+		if (n < 0) {
+			syslog(LOG_ERR, "read(%s, %d) failed. %s",
+				firmware, (int) sizeof(buf), strerror(errno));
+			goto out2;
+		}
+		if (n == 0)
+			break;
+
+		libusb20_tr_setup_bulk(bulk, buf, n, 3000);
+		libusb20_tr_start(bulk);
+
+		while (libusb20_dev_process(dev) == 0) {
+			if (libusb20_tr_pending(bulk) == 0)
+				break;
+
+			libusb20_dev_wait_process(dev, -1);
+		}
+
+		if (libusb20_tr_get_status(bulk) != 0) {
+			syslog(LOG_ERR, "bulk transfer failed with status %d",
+				libusb20_tr_get_status(bulk));
+			goto out2;
+		}
+	}
+
+	error = 0;
+out2:
+	close(fd);
+out1:
+	libusb20_tr_close(bulk);
+out:
+	libusb20_dev_close(dev);
+
+	return (error);
+}
+
+/*
+ * Display usage and exit
+ */
+
+static void
+usage(void)
+{
+	printf(
+"Usage: %s -d ugenX.Y -f firmware_file\n"
+"Usage: %s -h\n" \
+"Where:\n" \
+"\t-d ugenX.Y           ugen device name\n" \
+"\t-f firmware image    firmware image file name for download\n" \
+"\t-v vendor_id         vendor id\n" \
+"\t-p vendor_id         product id\n" \
+"\t-h                   display this message\n", ATH3KFW, ATH3KFW);
+
+        exit(255);
+}
+
diff --git a/usr.sbin/bcmfw/BCM-LEGAL.txt b/usr.sbin/bcmfw/BCM-LEGAL.txt
new file mode 100644
index 0000000000..daab5aebbb
--- /dev/null
+++ b/usr.sbin/bcmfw/BCM-LEGAL.txt
@@ -0,0 +1,8 @@
+$FreeBSD: head/usr.sbin/bluetooth/bcmfw/BCM-LEGAL.txt 114881 2003-05-10 22:03:45Z julian $
+
+BCM firmware version 2.15
+Copyright (c) 2000-2002 Broadcom Corporation
+
+Permission to distribute from..
+Contact info:
+        bluetooth_help@broadcom.com
diff --git a/usr.sbin/bcmfw/Makefile b/usr.sbin/bcmfw/Makefile
new file mode 100644
index 0000000000..1bdc531000
--- /dev/null
+++ b/usr.sbin/bcmfw/Makefile
@@ -0,0 +1,8 @@
+# $Id: Makefile,v 1.6 2003/08/14 20:05:58 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/bcmfw/Makefile 140941 2005-01-28 16:08:11Z ru $
+
+PROG=		bcmfw
+MAN=		bcmfw.8
+WARNS?=		2
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bcmfw/README b/usr.sbin/bcmfw/README
new file mode 100644
index 0000000000..0fc59b90ee
--- /dev/null
+++ b/usr.sbin/bcmfw/README
@@ -0,0 +1,22 @@
+$FreeBSD: head/usr.sbin/bluetooth/bcmfw/README 114900 2003-05-11 02:19:10Z julian $
+
+This directory will eventually also contain copies of the broadcom firmware.
+
+It WILL look like:
+total 190
+drwxr-xr-x   3 julian  wheel     512 May 10 00:40 .
+drwxr-xr-x  11 julian  wheel     512 May 10 14:48 ..
+-rw-r--r--   1 julian  wheel     154 May 10 00:41 BCM-LEGAL.txt
+-rw-r--r--   1 julian  wheel      56 May 10 00:14 BCM2033-FW.bin.md5
+-rw-r--r--   1 julian  wheel  158049 May 10 00:14 BCM2033-FW.bin.uue
+-rw-r--r--   1 julian  wheel      56 May 10 00:14 BCM2033-MD.hex.md5
+-rw-r--r--   1 julian  wheel    4505 May 10 00:14 BCM2033-MD.hex.uue
+drwxr-xr-x   2 julian  wheel     512 May 10 00:52 CVS
+-rw-r--r--   1 julian  wheel     516 May 10 00:14 Makefile
+-rw-r--r--   1 julian  wheel    3013 May 10 00:14 bcmfw.8
+-rw-r--r--   1 julian  wheel    6806 May 10 00:14 bcmfw.c
+
+Until then, the firmware files can be fetched as part of 
+ http://bluez.sourceforge.net/download/bluez-bluefw-0.9.tar.gz
+
+
diff --git a/usr.sbin/bcmfw/bcmfw.8 b/usr.sbin/bcmfw/bcmfw.8
new file mode 100644
index 0000000000..89edafd73a
--- /dev/null
+++ b/usr.sbin/bcmfw/bcmfw.8
@@ -0,0 +1,105 @@
+.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: bcmfw.8,v 1.7 2003/05/21 00:33:40 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/bcmfw/bcmfw.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd March 31, 2003
+.Dt BCMFW 8
+.Os
+.Sh NAME
+.Nm bcmfw
+.Nd firmware download utility for Broadcom BCM2033 chip based Bluetooth USB devices
+.Sh SYNOPSIS
+.Nm
+.Op Fl h
+.Fl f Ar firmware_file_name
+.Fl m Ar mini-driver_file_name
+.Fl n Ar device_name
+.Sh DESCRIPTION
+The
+.Nm
+utility downloads the specified mini-driver and firmware files to the specified
+device.
+.Pp
+This utility will
+.Em only
+work with Broadcom BCM2033 chip based Bluetooth USB devices.
+The identification is currently based on USB vendor ID/product ID pair.
+The vendor ID should be 0x0a5c
+.Pq Dv USB_VENDOR_BROADCOM
+and the product ID should be 0x2033.
+.Pp
+Due to copyright issues I will no longer provide mini-driver and firmware
+files for the device.
+These files can be obtained from the Linux BlueZ bluez-firmware package.
+.Pp
+Visit
+.Pa http://www.bluez.org/download.html
+for details.
+.Pp
+I am using the following files from the bluez-firmware-1.0 package:
+.Pp
+.Dl "MD5 (BCM2033-MD.hex) = 5580317158d07fc4ace90af04f8e1c73"
+.Dl "MD5 (BCM2033-FW.bin) = b4e142b3272cfe5a84b32fda6b4b032f"
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl f Ar firmware_file_name
+Specify firmware file name for download.
+.It Fl h
+Display usage message and exit.
+.It Fl m Ar mini-driver_file_name
+Specify mini-driver file name for download.
+.It Fl n Ar device_name
+Specify device name.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /dev/ubtbcmfw Ns Ar N Ns Pa \&. Ns Ar EE" -compact
+.It Pa BCM2033-MD.hex
+Mini-driver image.
+.It Pa BCM2033-FW.bin
+Firmware image.
+.It Pa /dev/ubtbcmfw Ns Ar N Ns Pa \&. Ns Ar EE
+Endpoint
+.Ar EE
+of device
+.Ar N .
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+To download the firmware into the
+.Pa /dev/ubtbcmfw0
+device:
+.Pp
+.Dl "bcmfw -n ubtbcmfw0 -m BCM2033-MD.hex -f BCM2033-FW.bin"
+.Sh SEE ALSO
+.Xr ubtbcmfw 4 ,
+.Xr ugen 4
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report if found.
diff --git a/usr.sbin/bcmfw/bcmfw.c b/usr.sbin/bcmfw/bcmfw.c
new file mode 100644
index 0000000000..d6971d03ea
--- /dev/null
+++ b/usr.sbin/bcmfw/bcmfw.c
@@ -0,0 +1,308 @@
+/*
+ * bcmfw.c
+ *
+ * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: bcmfw.c,v 1.4 2003/04/27 19:28:09 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bcmfw/bcmfw.c 188945 2009-02-23 18:36:54Z thompsa $
+ *
+ * Based on Linux BlueZ BlueFW-0.9 package
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usb_ioctl.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netgraph.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define BCMFW		"bcmfw"
+#define BCMFW_INTR_EP	1
+#define BCMFW_BULK_EP	2
+#define BCMFW_BSIZE	4096
+
+#define USB_VENDOR_BROADCOM 0x0a5c
+#define USB_PRODUCT_BROADCOM_BCM2033 0x2033
+
+static int bcmfw_check_device
+	(char const *name);
+static int bcmfw_load_firmware
+	(char const *name, char const *md, char const *fw);
+static void bcmfw_usage
+	(void);
+
+/*
+ * Main
+ */
+
+int
+main(int argc, char *argv[])
+{
+	char	*name = NULL, *md = NULL, *fw = NULL;
+	int	 x;
+
+	while ((x = getopt(argc, argv, "f:hn:m:")) != -1) {
+		switch (x) {
+		case 'f': /* firmware file */
+			fw = optarg;
+			break;
+
+		case 'n': /* name */
+			name = optarg;
+			break;
+
+		case 'm': /* Mini-driver */
+			md = optarg;
+			break;
+
+		case 'h':
+		default:
+			bcmfw_usage();
+			/* NOT REACHED */
+		}
+	}
+
+	if (name == NULL || md == NULL || fw == NULL)
+		bcmfw_usage();
+		/* NOT REACHED */
+
+	openlog(BCMFW, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_USER);
+
+	if (bcmfw_check_device(name) < 0)
+		exit(1);
+
+	if (bcmfw_load_firmware(name, md, fw) < 0)
+		exit(1);
+
+	closelog();
+
+	return (0);
+} /* main */
+
+/*
+ * Check device VendorID/ProductID
+ */
+
+static int
+bcmfw_check_device(char const *name)
+{
+	usb_device_descriptor_t	desc;
+	char			path[BCMFW_BSIZE];
+	int			fd = -1, error = -1;
+
+	snprintf(path, sizeof(path), "/dev/%s", name);
+
+	if ((fd = open(path, O_WRONLY)) < 0) {
+		syslog(LOG_ERR, "Could not open(%s). %s (%d)",
+				path, strerror(errno), errno);
+		goto out;
+	}
+
+	if (ioctl(fd, USB_GET_DEVICE_DESC, &desc) < 0) {
+		syslog(LOG_ERR, "Could not ioctl(%d, %ld, %p). %s (%d)",
+				fd, USB_GET_DEVICE_DESC, &desc,
+				strerror(errno), errno);
+		goto out;
+	}
+
+	if (UGETW(desc.idVendor) != USB_VENDOR_BROADCOM ||
+	    UGETW(desc.idProduct) != USB_PRODUCT_BROADCOM_BCM2033) {
+		syslog(LOG_ERR, "Unsupported device, VendorID=%#x, " \
+				"ProductID=%#x", UGETW(desc.idVendor),
+				UGETW(desc.idProduct));
+		error = -1;
+	} else
+		error = 0;
+out:
+	if (fd != -1)
+		close(fd);
+
+	return (error);
+} /* bcmfw_check_device */
+
+/*
+ * Download minidriver and firmware
+ */
+
+static int
+bcmfw_load_firmware(char const *name, char const *md, char const *fw)
+{
+	char	buf[BCMFW_BSIZE];
+	int	intr = -1, bulk = -1, fd = -1, error = -1, len;
+
+	/* Open interrupt endpoint device */
+	snprintf(buf, sizeof(buf), "/dev/%s.%d", name, BCMFW_INTR_EP);
+	if ((intr = open(buf, O_RDONLY)) < 0) {
+		syslog(LOG_ERR, "Could not open(%s). %s (%d)",
+				buf, strerror(errno), errno);
+		goto out;
+	}
+
+	/* Open bulk endpoint device */
+	snprintf(buf, sizeof(buf), "/dev/%s.%d", name, BCMFW_BULK_EP);
+	if ((bulk = open(buf, O_WRONLY)) < 0) {
+		syslog(LOG_ERR, "Could not open(%s). %s (%d)",
+				buf, strerror(errno), errno);
+		goto out;
+	}
+
+	/* 
+	 * Load mini-driver 
+	 */
+
+	if ((fd = open(md, O_RDONLY)) < 0) {
+		syslog(LOG_ERR, "Could not open(%s). %s (%d)",
+				md, strerror(errno), errno);
+		goto out;
+	}
+
+	for (;;) {
+		len = read(fd, buf, sizeof(buf));
+		if (len < 0) {
+			syslog(LOG_ERR, "Could not read(%s). %s (%d)",
+					md, strerror(errno), errno);
+			goto out;
+		}
+		if (len == 0)
+			break;
+
+		len = write(bulk, buf, len);
+		if (len < 0) {
+			syslog(LOG_ERR, "Could not write(/dev/%s.%d). %s (%d)",
+					name, BCMFW_BULK_EP, strerror(errno),
+					errno);
+			goto out;
+		}
+	}
+
+	close(fd);
+	fd = -1;
+
+	usleep(10);
+
+	/* 
+	 * Memory select 
+	 */
+
+	if (write(bulk, "#", 1) < 0) {
+		syslog(LOG_ERR, "Could not write(/dev/%s.%d). %s (%d)",
+				name, BCMFW_BULK_EP, strerror(errno), errno);
+		goto out;
+	}
+
+	if (read(intr, buf, sizeof(buf)) < 0) {
+		syslog(LOG_ERR, "Could not read(/dev/%s.%d). %s (%d)",
+				name, BCMFW_INTR_EP, strerror(errno), errno);
+		goto out;
+	}
+
+	if (buf[0] != '#') {
+		syslog(LOG_ERR, "%s: Memory select failed (%c)", name, buf[0]);
+		goto out;
+	}
+
+	/*
+	 * Load firmware
+	 */
+
+	if ((fd = open(fw, O_RDONLY)) < 0) {
+		syslog(LOG_ERR, "Could not open(%s). %s (%d)",
+				fw, strerror(errno), errno);
+		goto out;
+	}
+
+	for (;;) {
+		len = read(fd, buf, sizeof(buf));
+		if (len < 0) {
+			syslog(LOG_ERR, "Could not read(%s). %s (%d)",
+					fw, strerror(errno), errno);
+			goto out;
+		}
+		if (len == 0)
+			break;
+
+		len = write(bulk, buf, len);
+		if (len < 0) {
+			syslog(LOG_ERR, "Could not write(/dev/%s.%d). %s (%d)",
+					name, BCMFW_BULK_EP, strerror(errno),
+					errno);
+			goto out;
+		}
+	}
+
+	close(fd);
+	fd = -1;
+
+	if (read(intr, buf, sizeof(buf)) < 0) {
+		syslog(LOG_ERR, "Could not read(/dev/%s.%d). %s (%d)",
+				name, BCMFW_INTR_EP, strerror(errno), errno);
+		goto out;
+	}
+
+	if (buf[0] != '.') {
+		syslog(LOG_ERR, "%s: Could not load firmware (%c)",
+				name, buf[0]);
+		goto out;
+	}
+
+	usleep(500000);
+	error = 0;
+out:
+	if (fd != -1)
+		close(fd);
+	if (bulk != -1)
+		close(bulk);
+	if (intr != -1)
+		close(intr);
+
+	return (error);
+} /* bcmfw_load_firmware */
+
+/*
+ * Display usage message and quit
+ */
+
+static void 
+bcmfw_usage(void)
+{
+	fprintf(stdout,
+"Usage: %s -n name -m md_file -f fw_file\n"
+"Where:\n" \
+"\t-n name              device name\n" \
+"\t-m mini-driver       image mini-driver image file name for download\n" \
+"\t-f firmware image    firmware image file name for download\n" \
+"\t-h                   display this message\n", BCMFW);
+
+	exit(255);
+} /* bcmfw_usage */
+
diff --git a/usr.sbin/bt3cfw/Makefile b/usr.sbin/bt3cfw/Makefile
new file mode 100644
index 0000000000..a30b50fc12
--- /dev/null
+++ b/usr.sbin/bt3cfw/Makefile
@@ -0,0 +1,11 @@
+# $Id: Makefile,v 1.5 2003/08/14 20:06:00 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/bt3cfw/Makefile 140941 2005-01-28 16:08:11Z ru $
+
+PROG=		bt3cfw
+MAN=		bt3cfw.8
+WARNS?=		2
+
+DPADD=		${LIBNETGRAPH}
+LDADD=		-lnetgraph
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bt3cfw/bt3cfw.8 b/usr.sbin/bt3cfw/bt3cfw.8
new file mode 100644
index 0000000000..6532b0d445
--- /dev/null
+++ b/usr.sbin/bt3cfw/bt3cfw.8
@@ -0,0 +1,73 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: bt3cfw.8,v 1.4 2003/05/21 00:34:51 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/bt3cfw/bt3cfw.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd November 11, 2002
+.Dt BT3CFW 8
+.Os
+.Sh NAME
+.Nm bt3cfw
+.Nd firmware download utility for 3Com Bluetooth PC card driver
+.Sh SYNOPSIS
+.Nm
+.Op Fl h
+.Fl f Ar Firmware_file_name
+.Fl n Ar Netgraph_node_name
+.Sh DESCRIPTION
+The
+.Nm
+utility connects to the specified Netgraph driver node of type
+.Dv BTCCC
+and downloads the specified firmware file.
+.Pp
+Due to copyright issues, I will no longer provide firmware with the card
+driver.
+The firmware can be obtained from the Windows driver package that
+can be downloaded from the 3COM web site at no charge.
+The firmware name is
+.Pa BT3CPCC.BIN .
+I am using the original firmware that came with the card on CD-ROM.
+.Pp
+.Dl "MD5 (BT3CPCC.BIN) = 36170fda56ea9fdbf1702c966f8a97f1"
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl f Ar Firmware_file_name
+Specify firmware file name for download.
+.It Fl h
+Display usage message and exit.
+.It Fl n Ar Netgraph_node_name
+Connect to the specified Netgraph driver node of type
+.Dv BTCCC .
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr ng_bt3c 4
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Please report if found.
diff --git a/usr.sbin/bt3cfw/bt3cfw.c b/usr.sbin/bt3cfw/bt3cfw.c
new file mode 100644
index 0000000000..69130679a1
--- /dev/null
+++ b/usr.sbin/bt3cfw/bt3cfw.c
@@ -0,0 +1,228 @@
+/*
+ * bt3cfw.c
+ *
+ * Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: bt3cfw.c,v 1.2 2003/05/21 22:40:29 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bt3cfw/bt3cfw.c 227876 2011-11-23 10:27:18Z kevlo $
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <netgraph.h>
+#include <netgraph7/bluetooth/include/ng_bt3c.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define BT3CFW_IDENT			"bt3cfw"
+#define BT3CFW_MAX_FIRMWARE_SIZE	0xffff
+
+/* Convert hex ASCII to int4 */
+static int 
+hexa2int4(const char *a)
+{
+	if ('0' <= *a && *a <= '9')
+		return (*a - '0');
+
+	if ('A' <= *a && *a <= 'F')
+		return (*a - 'A' + 0xa);
+
+	if ('a' <= *a && *a <= 'f')
+		return (*a - 'a' + 0xa);
+
+	syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a);
+	exit(255);
+}
+
+/* Convert hex ASCII to int8 */
+static int 
+hexa2int8(const char *a)
+{
+	return ((hexa2int4(a) << 4) | hexa2int4(a + 1));
+} 
+
+/* Convert hex ASCII to int16 */
+static int 
+hexa2int16(const char *a)
+{
+	return ((hexa2int8(a) << 8) | hexa2int8(a + 2));
+} 
+
+/* Convert hex ASCII to int32 */
+static int 
+hexa2int32(const char *a)
+{
+	return ((hexa2int16(a) << 16) | hexa2int16(a + 4));
+}
+
+/* Display usage() and exit */
+static void
+usage(void)
+{
+	syslog(LOG_ERR, "Usage: %s -f FirmwareFile -n NodeName", BT3CFW_IDENT);
+	exit(255);
+}
+ 
+/* Main */
+int
+main(int argc, char *argv[])
+{
+	FILE	*firmware_file = NULL;
+	char	 buffer[80], path[NG_PATHSIZ],
+		*firmware_filename = NULL;
+	uint8_t	*firmware = NULL;
+	int	 firmware_size, opt, cs, ds;
+
+	memset(path, 0, sizeof(path));
+	openlog(BT3CFW_IDENT, LOG_NDELAY|LOG_PID|LOG_PERROR, LOG_USER);
+ 
+	while ((opt = getopt(argc, argv, "f:hn:")) != -1) {
+		switch (opt) {
+		case 'f':
+			firmware_filename = optarg;
+			break;
+  
+		case 'n':
+			snprintf(path, sizeof(path), "%s:", optarg);
+			break;
+
+		case 'h':
+		default:
+			usage();
+			/* NOT REACHED */
+		}
+	}
+
+	if (firmware_filename == NULL || path[0] == 0)
+		usage();
+		/* NOT REACHED */
+
+	firmware = (uint8_t *) calloc(BT3CFW_MAX_FIRMWARE_SIZE,
+					sizeof(uint8_t));
+	if (firmware == NULL) {
+		syslog(LOG_ERR, "Could not allocate firmware buffer");
+		exit(255);
+	}
+
+	if ((firmware_file = fopen(firmware_filename, "r")) == NULL) {
+		syslog(LOG_ERR, "Could not open BT3C firmware file %s. %s (%d)",
+				firmware_filename, strerror(errno), errno);
+		exit(255);
+	}
+
+	firmware_size = 0;
+
+	while (fgets(buffer, sizeof(buffer), firmware_file)) {
+		int     i, size, address, cs, fcs;
+
+		size = hexa2int8(buffer + 2);
+		address = hexa2int32(buffer + 4);
+		fcs = hexa2int8(buffer + 2 + size * 2);
+
+		if (buffer[1] == '3') {
+			ng_bt3c_firmware_block_ep	*block = NULL;
+			uint16_t			*data = NULL;
+
+			block = (ng_bt3c_firmware_block_ep *)
+						(firmware + firmware_size);
+
+			firmware_size += sizeof(*block);
+			if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) {
+				syslog(LOG_ERR, "Could not add new firmware " \
+						"block. Firmware file %s is " \
+						"too big, firmware_size=%d", 
+						firmware_filename,
+						firmware_size);
+				exit(255);
+			}
+
+			block->block_address = address;
+			block->block_size = (size - 4) / 2;
+			block->block_alignment = (block->block_size * 2) % 3;
+			if (block->block_alignment != 0)
+				block->block_alignment = 3 - block->block_alignment;
+
+			firmware_size += (block->block_size * 2);
+			firmware_size += block->block_alignment;
+			if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) {
+				syslog(LOG_ERR, "Could not add new firmware " \
+						"data. Firmware file %s is " \
+						"too big, firmware_size=%d", 
+						firmware_filename,
+						firmware_size);
+				exit(255);
+			}
+
+			/* First part of the cheksum: size and address */
+			cs = 0;
+			for (i = 0; i < 5; i++)
+				cs += hexa2int8(buffer + 2 + i * 2);
+
+			/* Data + second part of the cheksum: data */
+			data = (uint16_t *)(block + 1);
+			for (i = 0; i < block->block_size; i++) {
+				data[i] = hexa2int16(buffer + (i * 4) + 12);
+				cs += (((data[i] & 0xff00) >> 8) & 0xff);
+				cs += (data[i] & 0x00ff);
+			}
+		} else
+			for (cs = 0, i = 0; i < size; i++)
+				cs += hexa2int8(buffer + 2 + i * 2);
+
+		if (((cs + fcs) & 0xff) != 0xff) {
+			syslog(LOG_ERR, "Invalid firmware file %s. Checksum " \
+					"error, cs=%#x, fcs=%#x, checksum=%#x",
+					firmware_filename, (cs & 0xff), fcs,
+					((cs + fcs) & 0xff));
+			exit(255);
+		}
+	}
+
+	/* Send firmware to the card */
+	if (NgMkSockNode(NULL, &cs, &ds) < 0) {
+		syslog(LOG_ERR, "Could not create Netgraph socket. %s (%d)",
+				strerror(errno), errno);
+		exit(255);
+	}
+
+	if (NgSendMsg(cs, path, NGM_BT3C_COOKIE,
+			NGM_BT3C_NODE_DOWNLOAD_FIRMWARE,
+			(void const *) firmware, firmware_size) < 0) {
+		syslog(LOG_ERR, "Could not send Netgraph message. %s (%d)",
+				strerror(errno), errno);
+		exit(255);
+	}
+
+	free(firmware);
+	firmware = NULL;
+	fclose(firmware_file);
+
+	return (0);
+}
+
diff --git a/usr.sbin/btconfig/Makefile b/usr.sbin/btconfig/Makefile
deleted file mode 100644
index 44e0b16021..0000000000
--- a/usr.sbin/btconfig/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# $NetBSD: Makefile,v 1.2 2007/05/28 12:06:34 tls Exp $
-
-PROG=		btconfig
-MAN = 		btconfig.8
-
-CFLAGS+=	-I${.CURDIR}/../../sys
-DPADD+=		${LIBBLUETOOTH}
-LDADD+=		-lbluetooth
-
-.include <bsd.prog.mk>
diff --git a/usr.sbin/btconfig/btconfig.8 b/usr.sbin/btconfig/btconfig.8
deleted file mode 100644
index edb868555d..0000000000
--- a/usr.sbin/btconfig/btconfig.8
+++ /dev/null
@@ -1,178 +0,0 @@
-.\" $NetBSD: btconfig.8,v 1.7 2007/09/07 18:40:01 plunky Exp $
-.\" $DragonFly: src/usr.sbin/btconfig/btconfig.8,v 1.2 2008/01/09 09:03:34 swildner Exp $
-.\"
-.\" Copyright (c) 2006 Itronix Inc.
-.\" All rights reserved.
-.\"
-.\" Written by Iain Hibbert for Itronix Inc.
-.\"
-.\" 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. The name of Itronix Inc. may not be used to endorse
-.\"    or promote products derived from this software without specific
-.\"    prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
-.\"
-.Dd September 7, 2007
-.Dt BTCONFIG 8
-.Os
-.Sh NAME
-.Nm btconfig
-.Nd configure bluetooth devices
-.Sh SYNOPSIS
-.Nm
-.Op Fl svz
-.Oo
-.Ar device
-.Op Ar parameters
-.Oc
-.Nm
-.Op Fl l
-.Sh DESCRIPTION
-.Nm
-is used to configure Bluetooth devices.
-If the
-.Ar device
-is given, but no parameters, then
-.Nm
-will print information about the device.
-If no
-.Ar device
-is given, a basic list of devices will be printed.
-.Pp
-When the
-.Fl l
-flag is used, just the device names will be printed.
-.Sh COMMANDS
-The following parameters may be specified with
-.Nm :
-.Bl -tag -width xxxxxxxxxxx
-.It Cm up
-Enable Bluetooth Device.
-.It Cm down
-Disable Bluetooth Device.
-.It Cm pscan
-Enable Page Scan.
-This enables incoming connections to the device.
-.It Cm -pscan
-Disable Page Scan.
-.It Cm iscan
-Enable Inquiry Scan.
-This puts the device in Discoverable mode.
-.It Cm -iscan
-Disable Inquiry Scan.
-.It Cm encrypt
-Enable encryption.
-This will cause the device to request encryption on all baseband
-connections, and will only work if authentication is also enabled.
-.It Cm -encrypt
-Disable encryption.
-.It Cm auth
-Enable authentication.
-This will cause the device to request authentication
-for all baseband connections.
-.It Cm -auth
-Disable authentication.
-.It Cm switch
-Enable Role Switching.
-.It Cm -switch
-Disable Role Switching.
-.It Cm hold
-Enable Hold Mode.
-.It Cm -hold
-Disable Hold Mode.
-.It Cm sniff
-Enable Sniff Mode.
-.It Cm -sniff
-Disable Sniff Mode.
-.It Cm park
-Enable Park Mode.
-.It Cm -park
-Disable Park Mode.
-.It Cm name Ar name
-Set human readable name of device.
-.It Cm ptype Ar type
-Set packet types.
-.Ar type
-is a 16 bit hex value specifying packet types that will be requested
-by outgoing ACL connections.
-By default, all packet types that the device supports are enabled,
-see bluetooth specifications for more information if you want to change this.
-.It Cm class Ar class
-Set class of device.
-.Ar class
-is a 3 byte hex value the value of which declares the device capabilities.
-See Bluetooth Assigned Numbers documents at
-.Pa https://www.bluetooth.org/
-for details
-of constructing a "Class of Device" value.
-As a starter, 0x020104 means Desktop Computer, with Networking
-available.
-.It Cm fixed
-Set fixed pin type.
-.It Cm variable
-Set variable pin type.
-.It Cm inquiry
-Perform device Discovery from the specified device and print details.
-.It Cm rssi
-Enable Remote Signal Strength Indicator (RSSI) in inquiry results.
-This will only work if the device features indicate
-.Aq RSSI with inquiry result .
-.It Cm -rssi
-Disable Remote Signal Strength Indicator (RSSI) in inquiry results.
-.It Cm reset
-Perform a hard reset on the device and re-initialise system state.
-.It Cm voice
-Set Voice Setting.
-[This should be 0x0060 for now]
-.It Cm pto
-Set Page Timeout value.
-This is a decimal value in milliseconds.
-.It Cm scomtu
-Change SCO mtu value.
-This is a decimal value, see
-.Xr ubt 4
-for reasons why you may need to do this.
-.El
-.Pp
-All parameters are parsed before any device operations take place.
-Each time the
-.Fl v
-flag is given, verbosity levels will be increased.
-.Pp
-Super-user privileges are required to change device configurations.
-.Sh DIAGNOSTICS
-Messages indicating the specified device does not exist, the
-requested address is unknown, or the user is not privileged and
-tried to alter an device's configuration.
-.Sh SEE ALSO
-.Xr bluetooth 4 ,
-.Xr ubt 4
-.Sh HISTORY
-The
-.Nm
-command was written for
-.Nx 4.0
-by
-.An Iain Hibbert
-under the sponsorship of Itronix, Inc and was imported into
-.Dx 1.11 .
-.Sh BUGS
-The output is very messy.
diff --git a/usr.sbin/btconfig/btconfig.c b/usr.sbin/btconfig/btconfig.c
deleted file mode 100644
index 7437f197c1..0000000000
--- a/usr.sbin/btconfig/btconfig.c
+++ /dev/null
@@ -1,1173 +0,0 @@
-/* $NetBSD: btconfig.c,v 1.6 2007/09/07 18:40:01 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/types.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-
-#include <net/if.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <err.h>
-#include <bluetooth.h>
-#include <netbt/hci.h>
-#include <sys/endian.h>
-
-/* inquiry results storage */
-struct result {
-	bdaddr_t	bdaddr;
-	uint8_t		page_scan_rep_mode;
-	uint8_t		uclass[HCI_CLASS_SIZE];
-	uint16_t	clock_offset;
-	int8_t		rssi;
-};
-
-static void badarg(const char *) __dead2;
-static void badparam(const char *) __dead2;
-static void usage(void) __dead2;
-static int set_unit(unsigned long);
-static void config_unit(void);
-static void print_info(int);
-static void print_stats(void);
-static void print_class(const char *);
-static void print_voice(int);
-static void tag(const char *);
-static void print_features(const char *, uint8_t *);
-static void do_inquiry(void);
-static void print_result(int, struct result *, int);
-static void printb(uint16_t v, const char *bits);
-
-static void hci_req(uint16_t, uint8_t , void *, size_t, void *, size_t);
-#define save_value(opcode, cbuf, clen)	hci_req(opcode, 0, cbuf, clen, NULL, 0)
-#define load_value(opcode, rbuf, rlen)	hci_req(opcode, 0, NULL, 0, rbuf, rlen)
-#define hci_cmd(opcode, cbuf, clen)	hci_req(opcode, 0, cbuf, clen, NULL, 0)
-
-#define MAX_STR_SIZE	0xff
-
-/* print width */
-static int width = 0;
-#define MAX_WIDTH	70
-
-/* global variables */
-static int hci;
-static struct btreq btr;
-
-/* command line flags */
-static int verbose = 0;	/* more info */
-static int lflag = 0;	/* list devices */
-static int sflag = 0;	/* get/zero stats */
-
-/* device up/down (flag) */
-static int opt_enable = 0;
-static int opt_reset = 0;
-#define FLAGBITS	"\001UP"		\
-			"\002RUNNING"		\
-			"\003XMIT_CMD"		\
-			"\004XMIT_ACL"		\
-			"\005XMIT_SCO"		\
-			"\006INIT_BDADDR"	\
-			"\007INIT_BUFFER_SIZE"	\
-			"\010INIT_FEATURES"
-
-/* authorisation (flag) */
-static int opt_auth = 0;
-
-/* encryption (flag) */
-static int opt_encrypt = 0;
-
-/* scan enable options (flags) */
-static int opt_pscan = 0;
-static int opt_iscan = 0;
-
-/* link policy options (flags) */
-static int opt_switch = 0;
-static int opt_hold = 0;
-static int opt_sniff = 0;
-static int opt_park = 0;
-
-/* class of device (hex value) */
-static int opt_class = 0;
-static uint32_t class;
-
-/* packet type mask (hex value) */
-static int opt_ptype = 0;
-static uint32_t ptype;
-
-/* unit name (string) */
-static int opt_name = 0;
-static char name[MAX_STR_SIZE];
-
-/* pin type */
-static int opt_pin = 0;
-
-/* Inquiry */
-static int opt_rssi = 0;			/* inquiry_with_rssi (flag) */
-static int opt_inquiry = 0;
-#define INQUIRY_LENGTH		10	/* about 12 seconds */
-#define INQUIRY_MAX_RESPONSES	10
-
-/* Voice Settings */
-static int opt_voice = 0;
-static uint32_t voice;
-
-/* Page Timeout */
-static int opt_pto = 0;
-static uint32_t pto;
-
-/* set SCO mtu */
-static int opt_scomtu;
-static uint32_t scomtu;
-
-static struct parameter {
-	const char	*name;
-	enum { P_SET, P_CLR, P_STR, P_HEX, P_NUM } type;
-	int		*opt;
-	void		*val;
-} parameters[] = {
-	{ "up",		P_SET,	&opt_enable,	NULL	},
-	{ "enable",	P_SET,	&opt_enable,	NULL	},
-	{ "down",	P_CLR,	&opt_enable,	NULL	},
-	{ "disable",	P_CLR,	&opt_enable,	NULL	},
-	{ "name",	P_STR,	&opt_name,	name	},
-	{ "pscan",	P_SET,	&opt_pscan,	NULL	},
-	{ "-pscan",	P_CLR,	&opt_pscan,	NULL	},
-	{ "iscan",	P_SET,	&opt_iscan,	NULL	},
-	{ "-iscan",	P_CLR,	&opt_iscan,	NULL	},
-	{ "switch",	P_SET,	&opt_switch,	NULL	},
-	{ "-switch",	P_CLR,	&opt_switch,	NULL	},
-	{ "hold",	P_SET,	&opt_hold,	NULL	},
-	{ "-hold",	P_CLR,	&opt_hold,	NULL	},
-	{ "sniff",	P_SET,	&opt_sniff,	NULL	},
-	{ "-sniff",	P_CLR,	&opt_sniff,	NULL	},
-	{ "park",	P_SET,	&opt_park,	NULL	},
-	{ "-park",	P_CLR,	&opt_park,	NULL	},
-	{ "auth",	P_SET,	&opt_auth,	NULL	},
-	{ "-auth",	P_CLR,	&opt_auth,	NULL	},
-	{ "encrypt",	P_SET,	&opt_encrypt,	NULL	},
-	{ "-encrypt",	P_CLR,	&opt_encrypt,	NULL	},
-	{ "ptype",	P_HEX,	&opt_ptype,	&ptype	},
-	{ "class",	P_HEX,	&opt_class,	&class	},
-	{ "fixed",	P_SET,	&opt_pin,	NULL	},
-	{ "variable",	P_CLR,	&opt_pin,	NULL	},
-	{ "inq",	P_SET,	&opt_inquiry,	NULL	},
-	{ "inquiry",	P_SET,	&opt_inquiry,	NULL	},
-	{ "rssi",	P_SET,	&opt_rssi,	NULL	},
-	{ "-rssi",	P_CLR,	&opt_rssi,	NULL	},
-	{ "reset",	P_SET,	&opt_reset,	NULL	},
-	{ "voice",	P_HEX,	&opt_voice,	&voice	},
-	{ "pto",	P_NUM,	&opt_pto,	&pto	},
-	{ "scomtu",	P_NUM,	&opt_scomtu,	&scomtu	},
-	{ NULL,		0,	NULL,		NULL	}
-};
-
-int
-main(int ac, char *av[])
-{
-	int ch;
-	struct parameter *p;
-
-	while ((ch = getopt(ac, av, "hlsvz")) != -1) {
-		switch(ch) {
-		case 'l':
-			lflag = 1;
-			break;
-
-		case 's':
-			sflag = 1;
-			break;
-
-		case 'v':
-			verbose++;
-			break;
-
-		case 'z':
-			sflag = 2;
-			break;
-
-		case 'h':
-		default:
-			usage();
-		}
-	}
-	av += optind;
-	ac -= optind;
-
-	if (lflag && sflag)
-		usage();
-
-
-	hci = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 
-	if (hci == -1)
-		err(EXIT_FAILURE, "socket");
-
-	if (ac == 0) {
-		verbose++;
-
-		memset(&btr, 0, sizeof(btr));
-		while (set_unit(SIOCNBTINFO) != -1) {
-			print_info(99);
-			print_stats();
-		}
-
-		tag(NULL);
-	} else {
-		strlcpy(btr.btr_name, *av, HCI_DEVNAME_SIZE);
-		av++, ac--;
-
-		if (set_unit(SIOCGBTINFO) < 0)
-			err(EXIT_FAILURE, "%s", btr.btr_name);
-
-		if (ac == 0)
-			verbose += 2;
-
-		while (ac > 0) {
-			for (p = parameters ; ; p++) {
-				if (p->name == NULL)
-					badparam(*av);
-
-				if (strcmp(*av, p->name) == 0)
-					break;
-			}
-
-			switch(p->type) {
-			case P_SET:
-				*(p->opt) = 1;
-				break;
-
-			case P_CLR:
-				*(p->opt) = -1;
-				break;
-
-			case P_STR:
-				if (--ac < 1) badarg(p->name);
-				strlcpy((char *)(p->val), *++av, MAX_STR_SIZE);
-				*(p->opt) = 1;
-				break;
-
-			case P_HEX:
-				if (--ac < 1) badarg(p->name);
-				*(uint32_t *)(p->val) = strtoul(*++av, NULL, 16);
-				*(p->opt) = 1;
-				break;
-
-			case P_NUM:
-				if (--ac < 1) badarg(p->name);
-				*(uint32_t *)(p->val) = strtoul(*++av, NULL, 10);
-				*(p->opt) = 1;
-				break;
-			}
-
-			av++, ac--;
-		}
-
-		config_unit();
-		print_info(verbose);
-		print_stats();
-		do_inquiry();
-	}
-
-	close(hci);
-	return EXIT_SUCCESS;
-}
-
-static void
-badparam(const char *param)
-{
-	fprintf(stderr, "unknown parameter '%s'\n", param);
-	exit(EXIT_FAILURE);
-}
-
-static void
-badarg(const char *param)
-{
-	fprintf(stderr, "parameter '%s' needs argument\n", param);
-	exit(EXIT_FAILURE);
-}
-
-static void
-usage(void)
-{
-	fprintf(stderr, "usage:	%s [-svz] [device [parameters]]\n", getprogname());
-	fprintf(stderr, "	%s -l\n", getprogname());
-	exit(EXIT_FAILURE);
-}
-
-/*
- * pretty printing feature
- */
-static void
-tag(const char *f)
-{
-	if (f == NULL) {
-		if (width > 0)
-			printf("\n");
-
-		width = 0;
-	} else {
-		width += printf("%*s%s",
-				(width == 0 ? (lflag ? 0 : 8) : 1),
-				"", f);
-
-		if (width > MAX_WIDTH) {
-			printf("\n");
-			width = 0;
-		}
-	}
-}
-
-/*
- * basic HCI cmd request function with argument return.
- *
- * Normally, this will return on COMMAND_STATUS or COMMAND_COMPLETE for the given
- * opcode, but if event is given then it will ignore COMMAND_STATUS (unless error)
- * and wait for the specified event.
- *
- * if rbuf/rlen is given, results will be copied into the result buffer for
- * COMMAND_COMPLETE/event responses.
- */
-static void
-hci_req(uint16_t opcode, uint8_t event, void *cbuf, size_t clen, void *rbuf, size_t rlen)
-{
-	uint8_t msg[sizeof(hci_cmd_hdr_t) + HCI_CMD_PKT_SIZE];
-	hci_event_hdr_t *ep;
-	hci_cmd_hdr_t *cp;
-
-	cp = (hci_cmd_hdr_t *)msg;
-	cp->type = HCI_CMD_PKT;
-	cp->opcode = opcode = htole16(opcode);
-	cp->length = clen = MIN(clen, sizeof(msg) - sizeof(hci_cmd_hdr_t));
-
-	if (clen) memcpy((cp + 1), cbuf, clen);
-
-	if (send(hci, msg, sizeof(hci_cmd_hdr_t) + clen, 0) < 0)
-		err(EXIT_FAILURE, "HCI Send");
-
-	ep = (hci_event_hdr_t *)msg;
-	for(;;) {
-		if (recv(hci, msg, sizeof(msg), 0) < 0) {
-			if (errno == EAGAIN || errno == EINTR)
-				continue;
-
-			err(EXIT_FAILURE, "HCI Recv");
-		}
-
-		if (ep->event == HCI_EVENT_COMMAND_STATUS) {
-			hci_command_status_ep *cs;
-
-			cs = (hci_command_status_ep *)(ep + 1);
-			if (cs->opcode != opcode)
-				continue;
-
-			if (cs->status)
-				errx(EXIT_FAILURE,
-				    "HCI cmd (%4.4x) failed (status %d)",
-				    opcode, cs->status);
-
-			if (event == 0)
-				break;
-
-			continue;
-		}
-
-		if (ep->event == HCI_EVENT_COMMAND_COMPL) {
-			hci_command_compl_ep *cc;
-			uint8_t *ptr;
-
-			cc = (hci_command_compl_ep *)(ep + 1);
-			if (cc->opcode != opcode)
-				continue;
-
-			if (rbuf == NULL)
-				break;
-
-			ptr = (uint8_t *)(cc + 1);
-			if (*ptr)
-				errx(EXIT_FAILURE,
-				    "HCI cmd (%4.4x) failed (status %d)",
-				    opcode, *ptr);
-
-			memcpy(rbuf, ++ptr, rlen);
-			break;
-		}
-
-		if (ep->event == event) {
-			if (rbuf == NULL)
-				break;
-
-			memcpy(rbuf, (ep + 1), rlen);
-			break;
-		}
-	}
-}
-
-static int
-set_unit(unsigned long cmd)
-{
-	if (ioctl(hci, cmd, &btr) == -1)
-		return -1;
-
-	if (btr.btr_flags & BTF_UP) {
-		struct sockaddr_bt sa;
-
-		sa.bt_len = sizeof(sa);
-		sa.bt_family = AF_BLUETOOTH;
-		bdaddr_copy(&sa.bt_bdaddr, &btr.btr_bdaddr);
-
-		if (bind(hci, (struct sockaddr *)&sa, sizeof(sa)) < 0)
-			err(EXIT_FAILURE, "bind");
-			
-		if (connect(hci, (struct sockaddr *)&sa, sizeof(sa)) < 0)
-			err(EXIT_FAILURE, "connect");
-	}
-
-	return 0;
-}
-
-/*
- * apply configuration parameters to unit
- */
-static void
-config_unit(void)
-{
-	if (opt_enable) {
-		if (opt_enable > 0)
-			btr.btr_flags |= BTF_UP;
-		else
-			btr.btr_flags &= ~BTF_UP;
-
-		if (ioctl(hci, SIOCSBTFLAGS, &btr) < 0)
-			err(EXIT_FAILURE, "SIOCSBTFLAGS");
-
-		if (set_unit(SIOCGBTINFO) < 0)
-			err(EXIT_FAILURE, "%s", btr.btr_name);
-	}
-
-	if (opt_reset) {
-		hci_cmd(HCI_CMD_RESET, NULL, 0);
-
-		btr.btr_flags |= BTF_INIT;
-		if (ioctl(hci, SIOCSBTFLAGS, &btr) < 0)
-			err(EXIT_FAILURE, "SIOCSBTFLAGS");
-
-		/*
-		 * although the reset command will automatically
-		 * carry out these commands, we do them manually
-		 * just so we can wait for completion.
-		 */
-		hci_cmd(HCI_CMD_READ_BDADDR, NULL, 0);
-		hci_cmd(HCI_CMD_READ_BUFFER_SIZE, NULL, 0);
-		hci_cmd(HCI_CMD_READ_LOCAL_FEATURES, NULL, 0);
-
-		if (set_unit(SIOCGBTINFO) < 0)
-			err(EXIT_FAILURE, "%s", btr.btr_name);
-	}
-
-	if (opt_switch || opt_hold || opt_sniff || opt_park) {
-		uint16_t val = btr.btr_link_policy;
-
-		if (opt_switch > 0) val |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
-		if (opt_switch < 0) val &= ~HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
-		if (opt_hold > 0)   val |= HCI_LINK_POLICY_ENABLE_HOLD_MODE;
-		if (opt_hold < 0)   val &= ~HCI_LINK_POLICY_ENABLE_HOLD_MODE;
-		if (opt_sniff > 0)  val |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
-		if (opt_sniff < 0)  val &= ~HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
-		if (opt_park > 0)   val |= HCI_LINK_POLICY_ENABLE_PARK_MODE;
-		if (opt_park < 0)   val &= ~HCI_LINK_POLICY_ENABLE_PARK_MODE;
-
-		btr.btr_link_policy = val;
-		if (ioctl(hci, SIOCSBTPOLICY, &btr) < 0)
-			err(EXIT_FAILURE, "SIOCSBTPOLICY");
-	}
-
-	if (opt_ptype) {
-		btr.btr_packet_type = ptype;
-		if (ioctl(hci, SIOCSBTPTYPE, &btr) < 0)
-			err(EXIT_FAILURE, "SIOCSBTPTYPE");
-	}
-
-	if (opt_pscan || opt_iscan) {
-		uint8_t val;
-
-		load_value(HCI_CMD_READ_SCAN_ENABLE, &val, sizeof(val));
-		if (opt_pscan > 0) val |= HCI_PAGE_SCAN_ENABLE;
-		if (opt_pscan < 0) val &= ~HCI_PAGE_SCAN_ENABLE;
-		if (opt_iscan > 0) val |= HCI_INQUIRY_SCAN_ENABLE;
-		if (opt_iscan < 0) val &= ~HCI_INQUIRY_SCAN_ENABLE;
-		save_value(HCI_CMD_WRITE_SCAN_ENABLE, &val, sizeof(val));
-	}
-
-	if (opt_auth) {
-		uint8_t val = (opt_auth > 0 ? 1 : 0);
-
-		save_value(HCI_CMD_WRITE_AUTH_ENABLE, &val, sizeof(val));
-	}
-
-	if (opt_encrypt) {
-		uint8_t val = (opt_encrypt > 0 ? 1 : 0);
-
-		save_value(HCI_CMD_WRITE_ENCRYPTION_MODE, &val, sizeof(val));
-	}
-
-	if (opt_name)
-		save_value(HCI_CMD_WRITE_LOCAL_NAME, name, HCI_UNIT_NAME_SIZE);
-
-	if (opt_class) {
-		uint8_t val[HCI_CLASS_SIZE];
-
-		val[0] = (class >> 0) & 0xff;
-		val[1] = (class >> 8) & 0xff;
-		val[2] = (class >> 16) & 0xff;
-
-		save_value(HCI_CMD_WRITE_UNIT_CLASS, val, HCI_CLASS_SIZE);
-	}
-
-	if (opt_pin) {
-		uint8_t val;
-
-		if (opt_pin > 0)	val = 1;
-		else			val = 0;
-
-		save_value(HCI_CMD_WRITE_PIN_TYPE, &val, sizeof(val));
-	}
-
-	if (opt_voice) {
-		uint16_t val;
-
-		val = htole16(voice & 0x03ff);
-		save_value(HCI_CMD_WRITE_VOICE_SETTING, &val, sizeof(val));
-	}
-
-	if (opt_pto) {
-		uint16_t val;
-
-		val = htole16(pto * 8 / 5);
-		save_value(HCI_CMD_WRITE_PAGE_TIMEOUT, &val, sizeof(val));
-	}
-
-	if (opt_scomtu) {
-		if (scomtu > 0xff) {
-			warnx("Invalid SCO mtu %d", scomtu);
-		} else {
-			btr.btr_sco_mtu = scomtu;
-
-			if (ioctl(hci, SIOCSBTSCOMTU, &btr) < 0)
-				warn("SIOCSBTSCOMTU");
-		}
-	}
-
-	if (opt_rssi) {
-		uint8_t val = (opt_rssi > 0 ? 1 : 0);
-
-		save_value(HCI_CMD_WRITE_INQUIRY_MODE, &val, sizeof(val));
-	}
-}
-
-/*
- * Print info for Bluetooth Device with varying verbosity levels
- */
-static void
-print_info(int level)
-{
-	uint8_t val, buf[MAX_STR_SIZE];
-	uint16_t val16;
-
-	if (lflag) {
-		tag(btr.btr_name);
-		return;
-	}
-
-	if (level-- < 1)
-		return;
-
-	printf("%s: bdaddr %s flags %#x", btr.btr_name,
-		bt_ntoa(&btr.btr_bdaddr, NULL), btr.btr_flags);
-	printb(btr.btr_flags, FLAGBITS);
-	printf("\n");
-
-	if (level-- < 1)
-		return;
-
-	printf("\tnum_cmd = %d\n"
-	       "\tnum_acl = %d, acl_mtu = %d\n"
-	       "\tnum_sco = %d, sco_mtu = %d\n",
-	       btr.btr_num_cmd,
-	       btr.btr_num_acl, btr.btr_acl_mtu,
-	       btr.btr_num_sco, btr.btr_sco_mtu);
-
-	if (level-- < 1 || (btr.btr_flags & BTF_UP) == 0)
-		return;
-
-	load_value(HCI_CMD_READ_UNIT_CLASS, buf, HCI_CLASS_SIZE);
-	class = (buf[2] << 16) | (buf[1] << 8) | (buf[0]);
-	print_class("\t");
-
-	load_value(HCI_CMD_READ_LOCAL_NAME, buf, HCI_UNIT_NAME_SIZE);
-	printf("\tname: \"%s\"\n", buf);
-
-	load_value(HCI_CMD_READ_VOICE_SETTING, buf, sizeof(uint16_t));
-	voice = (buf[1] << 8) | buf[0];
-	print_voice(level);
-
-	load_value(HCI_CMD_READ_PIN_TYPE, &val, sizeof(val));
-	printf("\tpin: %s\n", val ? "fixed" : "variable");
-
-	width = printf("\toptions:");
-
-	load_value(HCI_CMD_READ_SCAN_ENABLE, &val, sizeof(val));
-	if (val & HCI_INQUIRY_SCAN_ENABLE)	tag("iscan");
-	else if (level > 0)			tag("-iscan");
-
-	if (val & HCI_PAGE_SCAN_ENABLE)		tag("pscan");
-	else if (level > 0)			tag("-pscan");
-
-	load_value(HCI_CMD_READ_AUTH_ENABLE, &val, sizeof(val));
-	if (val)				tag("auth");
-	else if (level > 0)			tag("-auth");
-
-	load_value(HCI_CMD_READ_ENCRYPTION_MODE, &val, sizeof(val));
-	if (val)				tag("encrypt");
-	else if (level > 0)			tag("-encrypt");
-
-	val = btr.btr_link_policy;
-	if (val & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH)	tag("switch");
-	else if (level > 0)				tag("-switch");
-	if (val & HCI_LINK_POLICY_ENABLE_HOLD_MODE)	tag("hold");
-	else if (level > 0)				tag("-hold");
-	if (val & HCI_LINK_POLICY_ENABLE_SNIFF_MODE)	tag("sniff");
-	else if (level > 0)				tag("-sniff");
-	if (val & HCI_LINK_POLICY_ENABLE_PARK_MODE)	tag("park");
-	else if (level > 0)				tag("-park");
-
-	load_value(HCI_CMD_READ_INQUIRY_MODE, &val, sizeof(val));
-	if (val)				tag("rssi");
-	else if (level > 0)			tag("-rssi");
-
-	tag(NULL);
-
-	if (level-- < 1)
-		return;
-
-	ptype = btr.btr_packet_type;
-	width = printf("\tptype: [0x%04x]", ptype);
-	if (ptype & HCI_PKT_DM1)		tag("DM1");
-	if (ptype & HCI_PKT_DH1)		tag("DH1");
-	if (ptype & HCI_PKT_DM3)		tag("DM3");
-	if (ptype & HCI_PKT_DH3)		tag("DH3");
-	if (ptype & HCI_PKT_DM5)		tag("DM5");
-	if (ptype & HCI_PKT_DH5)		tag("DH5");
-	if ((ptype & HCI_PKT_2MBPS_DH1) == 0)	tag("2-DH1");
-	if ((ptype & HCI_PKT_3MBPS_DH1) == 0)	tag("3-DH1");
-	if ((ptype & HCI_PKT_2MBPS_DH3) == 0)	tag("2-DH3");
-	if ((ptype & HCI_PKT_3MBPS_DH3) == 0)	tag("3-DH3");
-	if ((ptype & HCI_PKT_2MBPS_DH5) == 0)	tag("2-DH5");
-	if ((ptype & HCI_PKT_3MBPS_DH5) == 0)	tag("3-DH5");
-	tag(NULL);
-
-	load_value(HCI_CMD_READ_PAGE_TIMEOUT, &val16, sizeof(val16));
-	printf("\tpage timeout: %d ms\n", val16 * 5 / 8);
-
-	if (level-- < 1)
-		return;
-
-	load_value(HCI_CMD_READ_LOCAL_FEATURES, buf, HCI_FEATURES_SIZE);
-	print_features("\tfeatures:", buf);
-}
-
-static void
-print_stats(void)
-{
-	if (sflag == 0)
-		return;
-
-	if (sflag == 1) {
-		if (ioctl(hci, SIOCGBTSTATS, &btr) < 0)
-			err(EXIT_FAILURE, "SIOCGBTSTATS");
-	} else  {
-		if (ioctl(hci, SIOCZBTSTATS, &btr) < 0)
-			err(EXIT_FAILURE, "SIOCZBTSTATS");
-	}
-
-	printf( "\tTotal bytes sent %d, received %d\n"
-		"\tCommands sent %d, Events received %d\n"
-		"\tACL data packets sent %d, received %d\n"
-		"\tSCO data packets sent %d, received %d\n"
-		"\tInput errors %d, Output errors %d\n",
-		btr.btr_stats.byte_tx, btr.btr_stats.byte_rx,
-		btr.btr_stats.cmd_tx, btr.btr_stats.evt_rx,
-		btr.btr_stats.acl_tx, btr.btr_stats.acl_rx,
-		btr.btr_stats.sco_tx, btr.btr_stats.sco_rx,
-		btr.btr_stats.err_rx, btr.btr_stats.err_tx);
-}
-
-static void
-print_features(const char *str, uint8_t *f)
-{
-	width = printf("%s", str);
-
-	/* ------------------- byte 0 --------------------*/
-	if (*f & HCI_LMP_3SLOT)		    tag("<3 slot>");
-	if (*f & HCI_LMP_5SLOT)		    tag("<5 slot>");
-	if (*f & HCI_LMP_ENCRYPTION)	    tag("<encryption>");
-	if (*f & HCI_LMP_SLOT_OFFSET)	    tag("<slot offset>");
-	if (*f & HCI_LMP_TIMIACCURACY)	    tag("<timing accuracy>");
-	if (*f & HCI_LMP_ROLE_SWITCH)	    tag("<role switch>");
-	if (*f & HCI_LMP_HOLD_MODE)	    tag("<hold mode>");
-	if (*f & HCI_LMP_SNIFF_MODE)	    tag("<sniff mode>");
-	f++;
-
-	/* ------------------- byte 1 --------------------*/
-	if (*f & HCI_LMP_PARK_MODE)	    tag("<park mode>");
-	if (*f & HCI_LMP_RSSI)		    tag("<RSSI>");
-	if (*f & HCI_LMP_CHANNEL_QUALITY)   tag("<channel quality>");
-	if (*f & HCI_LMP_SCO_LINK)	    tag("<SCO link>");
-	if (*f & HCI_LMP_HV2_PKT)	    tag("<HV2>");
-	if (*f & HCI_LMP_HV3_PKT)	    tag("<HV3>");
-	if (*f & HCI_LMP_ULAW_LOG)	    tag("<u-Law log>");
-	if (*f & HCI_LMP_ALAW_LOG)	    tag("<A-Law log>");
-	f++;
-
-	/* ------------------- byte 1 --------------------*/
-	if (*f & HCI_LMP_CVSD)		    tag("<CVSD data>");
-	if (*f & HCI_LMP_PAGISCHEME)	    tag("<paging parameter>");
-	if (*f & HCI_LMP_POWER_CONTROL)	    tag("<power control>");
-	if (*f & HCI_LMP_TRANSPARENT_SCO)   tag("<transparent SCO>");
-	if (*f & HCI_LMP_FLOW_CONTROL_LAG0) tag("<flow control lag 0>");
-	if (*f & HCI_LMP_FLOW_CONTROL_LAG1) tag("<flow control lag 1>");
-	if (*f & HCI_LMP_FLOW_CONTROL_LAG2) tag("<flow control lag 2>");
-	if (*f & HCI_LMP_BC_ENCRYPTION)	    tag("<broadcast encryption>");
-	f++;
-
-	/* ------------------- byte 3 --------------------*/
-	if (*f & HCI_LMP_EDR_ACL_2MBPS)	    tag("<EDR ACL 2Mbps>");
-	if (*f & HCI_LMP_EDR_ACL_3MBPS)	    tag("<EDR ACL 3Mbps>");
-	if (*f & HCI_LMP_ENHANCED_ISCAN)    tag("<enhanced inquiry scan>");
-	if (*f & HCI_LMP_INTERLACED_ISCAN)  tag("<interlaced inquiry scan>");
-	if (*f & HCI_LMP_INTERLACED_PSCAN)  tag("<interlaced page scan>");
-	if (*f & HCI_LMP_RSSI_INQUIRY)	    tag("<RSSI with inquiry result>");
-	if (*f & HCI_LMP_EV3_PKT)	    tag("<EV3 packets>");
-	f++;
-
-	/* ------------------- byte 4 --------------------*/
-	if (*f & HCI_LMP_EV4_PKT)	    tag("<EV4 packets>");
-	if (*f & HCI_LMP_EV5_PKT)	    tag("<EV5 packets>");
-	if (*f & HCI_LMP_AFH_CAPABLE_SLAVE) tag("<AFH capable slave>");
-	if (*f & HCI_LMP_AFH_CLASS_SLAVE)   tag("<AFH class slave>");
-	if (*f & HCI_LMP_3SLOT_EDR_ACL)	    tag("<3 slot EDR ACL>");
-	f++;
-
-	/* ------------------- byte 5 --------------------*/
-	if (*f & HCI_LMP_5SLOT_EDR_ACL)	    tag("<5 slot EDR ACL>");
-	if (*f & HCI_LMP_AFH_CAPABLE_MASTER)tag("<AFH capable master>");
-	if (*f & HCI_LMP_AFH_CLASS_MASTER)  tag("<AFH class master>");
-	if (*f & HCI_LMP_EDR_eSCO_2MBPS)    tag("<EDR eSCO 2Mbps>");
-	if (*f & HCI_LMP_EDR_eSCO_3MBPS)    tag("<EDR eSCO 3Mbps>");
-	if (*f & HCI_LMP_3SLOT_EDR_eSCO)    tag("<3 slot EDR eSCO>");
-	f++;
-
-	/* ------------------- byte 6 --------------------*/
-	f++;
-
-	/* ------------------- byte 7 --------------------*/
-	if (*f & HCI_LMP_EXTENDED_FEATURES) tag("<extended features>");
-
-	tag(NULL);
-}
-
-static void
-print_class(const char *str)
-{
-	int major, minor;
-
-	major = (class & 0x1f00) >> 8;
-	minor = (class & 0x00fc) >> 2;
-
-	width = printf("%sclass: [0x%6.6x]", str, class);
-
-	switch (major) {
-	case 1:	/* Computer */
-		switch (minor) {
-		case 1: tag("Desktop");				break;
-		case 2: tag("Server");				break;
-		case 3: tag("Laptop");				break;
-		case 4: tag("Handheld");			break;
-		case 5: tag("Palm Sized");			break;
-		case 6: tag("Wearable");			break;
-		}
-		tag("Computer");
-		break;
-
-	case 2:	/* Phone */
-		switch (minor) {
-		case 1: tag("Cellular Phone");			break;
-		case 2: tag("Cordless Phone");			break;
-		case 3: tag("Smart Phone");			break;
-		case 4: tag("Wired Modem/Phone Gateway");	break;
-		case 5: tag("Common ISDN");			break;
-		default:tag("Phone");				break;
-		}
-		break;
-
-	case 3:	/* LAN */
-		tag("LAN");
-		switch ((minor & 0x38) >> 3) {
-		case 0: tag("[Fully available]");		break;
-		case 1: tag("[1-17% utilised]");		break;
-		case 2: tag("[17-33% utilised]");		break;
-		case 3: tag("[33-50% utilised]");		break;
-		case 4: tag("[50-67% utilised]");		break;
-		case 5: tag("[67-83% utilised]");		break;
-		case 6: tag("[83-99% utilised]");		break;
-		case 7: tag("[No service available]");		break;
-		}
-		break;
-
-	case 4:	/* Audio/Visual */
-		switch (minor) {
-		case 1: tag("Wearable Headset");		break;
-		case 2: tag("Hands-free Audio");		break;
-		case 4: tag("Microphone");			break;
-		case 5: tag("Loudspeaker");			break;
-		case 6: tag("Headphones");			break;
-		case 7: tag("Portable Audio");			break;
-		case 8: tag("Car Audio");			break;
-		case 9: tag("Set-top Box");			break;
-		case 10: tag("HiFi Audio");			break;
-		case 11: tag("VCR");				break;
-		case 12: tag("Video Camera");			break;
-		case 13: tag("Camcorder");			break;
-		case 14: tag("Video Monitor");			break;
-		case 15: tag("Video Display and Loudspeaker");	break;
-		case 16: tag("Video Conferencing");		break;
-		case 18: tag("A/V [Gaming/Toy]");		break;
-		default: tag("Audio/Visual");			break;
-		}
-		break;
-
-	case 5:	/* Peripheral */
-		switch (minor & 0x0f) {
-		case 1: tag("Joystick");			break;
-		case 2: tag("Gamepad");				break;
-		case 3: tag("Remote Control");			break;
-		case 4: tag("Sensing Device");			break;
-		case 5: tag("Digitiser Tablet");		break;
-		case 6: tag("Card Reader");			break;
-		default: tag("Peripheral");			break;
-		}
-
-		if (minor & 0x10) tag("Keyboard");
-		if (minor & 0x20) tag("Mouse");
-		break;
-
-	case 6:	/* Imaging */
-		if (minor & 0x20) tag("Printer");
-		if (minor & 0x10) tag("Scanner");
-		if (minor & 0x08) tag("Camera");
-		if (minor & 0x04) tag("Display");
-		if ((minor & 0x3c) == 0) tag("Imaging");
-		break;
-
-	case 7:	/* Wearable */
-		switch (minor) {
-		case 1: tag("Wrist Watch");			break;
-		case 2: tag("Pager");				break;
-		case 3: tag("Jacket");				break;
-		case 4: tag("Helmet");				break;
-		case 5: tag("Glasses");				break;
-		default: tag("Wearable");			break;
-		}
-		break;
-
-	case 8:	/* Toy */
-		switch (minor) {
-		case 1: tag("Robot");				break;
-		case 2: tag("Vehicle");				break;
-		case 3: tag("Doll / Action Figure");		break;
-		case 4: tag("Controller");			break;
-		case 5: tag("Game");				break;
-		default: tag("Toy");				break;
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	if (class & 0x002000)	tag("<Limited Discoverable>");
-	if (class & 0x010000)	tag("<Positioning>");
-	if (class & 0x020000)	tag("<Networking>");
-	if (class & 0x040000)	tag("<Rendering>");
-	if (class & 0x080000)	tag("<Capturing>");
-	if (class & 0x100000)	tag("<Object Transfer>");
-	if (class & 0x200000)	tag("<Audio>");
-	if (class & 0x400000)	tag("<Telephony>");
-	if (class & 0x800000)	tag("<Information>");
-	tag(NULL);
-}
-
-static void
-print_voice(int level)
-{
-	printf("\tvoice: [0x%4.4x]\n", voice);
-
-	if (level == 0)
-		return;
-
-	printf("\t\tInput Coding: ");
-	switch ((voice & 0x0300) >> 8) {
-	case 0x00:	printf("Linear PCM [%d-bit, pos %d]",
-			(voice & 0x0020 ? 16 : 8),
-			(voice & 0x001c) >> 2);		break;
-	case 0x01:	printf("u-Law");		break;
-	case 0x02:	printf("A-Law");		break;
-	case 0x03:	printf("unknown");		break;
-	}
-
-	switch ((voice & 0x00c0) >> 6) {
-	case 0x00:	printf(", 1's complement");	break;
-	case 0x01:	printf(", 2's complement");	break;
-	case 0x02:	printf(", sign magnitude");	break;
-	case 0x03:	printf(", unsigned");		break;
-	}
-
-	printf("\n\t\tAir Coding: ");
-	switch (voice & 0x0003) {
-	case 0x00:	printf("CVSD");			break;
-	case 0x01:	printf("u-Law");		break;
-	case 0x02:	printf("A-Law");		break;
-	case 0x03:	printf("Transparent");		break;
-	}
-
-	printf("\n");
-}
-
-static void
-print_result(int num, struct result *r, int rssi)
-{
-	hci_remote_name_req_cp ncp;
-	hci_remote_name_req_compl_ep nep;
-#if 0
-	hci_read_remote_features_cp fcp;
-	hci_read_remote_features_compl_ep fep;
-	struct hostent *hp;
-#endif
-
-	printf("%3d: bdaddr %s",
-			num,
-			bt_ntoa(&r->bdaddr, NULL));
-
-#if 0
-	hp = bt_gethostbyaddr(&r->bdaddr, sizeof(bdaddr_t), AF_BLUETOOTH);
-	if (hp != NULL)
-		printf(" (%s)", hp->h_name);
-#endif
-	printf("\n");
-
-	memset(&ncp, 0, sizeof(ncp));
-	bdaddr_copy(&ncp.bdaddr, &r->bdaddr);
-	ncp.page_scan_rep_mode = r->page_scan_rep_mode;
-	ncp.clock_offset = r->clock_offset;
-
-	hci_req(HCI_CMD_REMOTE_NAME_REQ,
-		HCI_EVENT_REMOTE_NAME_REQ_COMPL,
-		&ncp, sizeof(ncp),
-		&nep, sizeof(nep));
-
-	printf("   : name \"%s\"\n", nep.name);
-
-	class = (r->uclass[2] << 16) | (r->uclass[1] << 8) | (r->uclass[0]);
-	print_class("   : ");
-
-#if 0
-	hci_req(HCI_CMD_READ_REMOTE_FEATURES,
-		HCI_EVENT_READ_REMOTE_FEATURES_COMPL,
-		&fcp, sizeof(fcp),
-		&fep, sizeof(fep));
-
-	print_features("   : features", fep.features);
-#endif
-
-	printf("   : page scan rep mode 0x%02x\n", r->page_scan_rep_mode);
-	printf("   : clock offset %d\n", le16toh(r->clock_offset));
-
-	if (rssi)
-		printf("   : rssi %d\n", r->rssi);
-
-	printf("\n");
-}
-
-static void
-do_inquiry(void)
-{
-	uint8_t buf[HCI_EVENT_PKT_SIZE];
-	struct result result[INQUIRY_MAX_RESPONSES];
-	hci_inquiry_cp inq;
-	struct hci_filter f;
-	hci_event_hdr_t *hh;
-	int i, j, num, rssi;
-
-	if (opt_inquiry == 0)
-		return;
-
-	printf("Device Discovery from device: %s ...", btr.btr_name);
-	fflush(stdout);
-
-	memset(&f, 0, sizeof(f));
-	hci_filter_set(HCI_EVENT_COMMAND_STATUS, &f);
-	hci_filter_set(HCI_EVENT_COMMAND_COMPL, &f);
-	hci_filter_set(HCI_EVENT_INQUIRY_RESULT, &f);
-	hci_filter_set(HCI_EVENT_RSSI_RESULT, &f);
-	hci_filter_set(HCI_EVENT_INQUIRY_COMPL, &f);
-	hci_filter_set(HCI_EVENT_REMOTE_NAME_REQ_COMPL, &f);
-	hci_filter_set(HCI_EVENT_READ_REMOTE_FEATURES_COMPL, &f);
-	if (setsockopt(hci, BTPROTO_HCI, SO_HCI_EVT_FILTER, &f, sizeof(f)) < 0)
-		err(EXIT_FAILURE, "Can't set event filter");
-
-	/* General Inquiry LAP is 0x9e8b33 */
-	inq.lap[0] = 0x33;
-	inq.lap[1] = 0x8b;
-	inq.lap[2] = 0x9e;
-	inq.inquiry_length = INQUIRY_LENGTH;
-	inq.num_responses = INQUIRY_MAX_RESPONSES;
-
-	hci_cmd(HCI_CMD_INQUIRY, &inq, sizeof(inq));
-
-	num = 0;
-	rssi = 0;
-	hh = (hci_event_hdr_t *)buf;
-
-	for (;;) {
-		if (recv(hci, buf, sizeof(buf), 0) <= 0)
-			err(EXIT_FAILURE, "recv");
-
-		if (hh->event == HCI_EVENT_INQUIRY_COMPL)
-			break;
-
-		if (hh->event == HCI_EVENT_INQUIRY_RESULT) {
-			hci_inquiry_result_ep *ep = (hci_inquiry_result_ep *)(hh + 1);
-			hci_inquiry_response *ir = (hci_inquiry_response *)(ep + 1);
-
-			for (i = 0 ; i < ep->num_responses ; i++) {
-				if (num == INQUIRY_MAX_RESPONSES)
-					break;
-
-				/* some devices keep responding, ignore dupes */
-				for (j = 0 ; j < num ; j++)
-					if (bdaddr_same(&result[j].bdaddr, &ir[i].bdaddr))
-						break;
-
-				if (j < num)
-					continue;
-
-				bdaddr_copy(&result[num].bdaddr, &ir[i].bdaddr);
-				memcpy(&result[num].uclass, &ir[i].uclass, HCI_CLASS_SIZE);
-				result[num].page_scan_rep_mode = ir[i].page_scan_rep_mode;
-				result[num].clock_offset = ir[i].clock_offset;
-				result[num].rssi = 0;
-				num++;
-				printf(".");
-				fflush(stdout);
-			}
-			continue;
-		}
-#if 0
-		if (hh->event == HCI_EVENT_RSSI_RESULT) {
-			hci_rssi_result_ep *ep = (hci_rssi_result_ep *)(hh + 1);
-			hci_rssi_response *rr = (hci_rssi_response *)(ep + 1);
-
-			for (i = 0 ; i < ep->num_responses ; i++) {
-				if (num == INQUIRY_MAX_RESPONSES)
-					break;
-
-				/* some devices keep responding, ignore dupes */
-				for (j = 0 ; j < num ; j++)
-					if (bdaddr_same(&result[j].bdaddr, &rr[i].bdaddr))
-						break;
-
-				if (j < num)
-					continue;
-
-				bdaddr_copy(&result[num].bdaddr, &rr[i].bdaddr);
-				memcpy(&result[num].uclass, &rr[i].uclass, HCI_CLASS_SIZE);
-				result[num].page_scan_rep_mode = rr[i].page_scan_rep_mode;
-				result[num].clock_offset = rr[i].clock_offset;
-				result[num].rssi = rr[i].rssi;
-				rssi = 1;
-				num++;
-				printf(".");
-				fflush(stdout);
-			}
-			continue;
-		}
-#endif
-	}
-
-	printf(" %d response%s\n", num, (num == 1 ? "" : "s"));
-
-	for (i = 0 ; i < num ; i++)
-		print_result(i + 1, &result[i], rssi);
-}
-
-/*
- * Print a value a la the %pb%i format of the kernel's kprintf() borrowed
- * from ifconfig(8).
- */
-static void
-printb(uint16_t v, const char *bits)
-{
-	int i, any = 0;
-	char c;
-
-	if (bits) {
-		putchar('<');
-		while ((i = *bits++) != '\0') {
-			if (v & (1 << (i-1))) {
-				if (any)
-					putchar(',');
-				any = 1;
-				for (; (c = *bits) > 32; bits++)
-					putchar(c);
-			} else
-				for (; *bits > 32; bits++)
-					;
-		}
-		putchar('>');
-	}
-}
-
diff --git a/usr.sbin/bthcid/Makefile b/usr.sbin/bthcid/Makefile
deleted file mode 100644
index 4aac99afc1..0000000000
--- a/usr.sbin/bthcid/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# $NetBSD: Makefile,v 1.4 2007/05/28 12:06:34 tls Exp $
-# $DragonFly: src/usr.sbin/bthcid/Makefile,v 1.1 2008/01/30 14:10:19 hasso Exp $
-
-PROG=		bthcid
-MAN=		bthcid.8 bthcid.conf.5
-SRCS=		bthcid.c hci.c client.c config.c lexer.l parser.y
-
-DPADD+=		${LIBBLUETOOTH} ${LIBUTIL}
-LDADD+=		-lbluetooth -lutil
-CFLAGS+=	-I${.CURDIR}/../../sys -I${.CURDIR}
-
-.include <bsd.prog.mk>
diff --git a/usr.sbin/bthcid/bthcid.8 b/usr.sbin/bthcid/bthcid.8
deleted file mode 100644
index 5d7ab12d9f..0000000000
--- a/usr.sbin/bthcid/bthcid.8
+++ /dev/null
@@ -1,173 +0,0 @@
-.\" $NetBSD: bthcid.8,v 1.5 2006/10/03 02:04:42 wiz Exp $
-.\"
-.\" Copyright (c) 2006 Itronix Inc.
-.\" 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. The name of Itronix Inc. may not be used to endorse
-.\"    or promote products derived from this software without specific
-.\"    prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
-.\" 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.
-.\"
-.\" $Id: bthcid.8,v 1.1.1.1 2007/11/20 11:56:11 griffin Exp $
-.\" $FreeBSD: src/usr.sbin/bluetooth/hcsecd/hcsecd.8,v 1.6 2006/02/11 15:36:37 markus Exp $
-.\"
-.Dd September 29, 2006
-.Dt BTHCID 8
-.Os
-.Sh NAME
-.Nm bthcid
-.Nd Bluetooth Link Key/PIN Code Manager
-.Sh SYNOPSIS
-.Nm
-.Op Fl fn
-.Op Fl d Ar device
-.Op Fl m Ar mode
-.Op Fl s Ar socket_name
-.Nm
-.Op Fl h
-.Sh DESCRIPTION
-The
-.Nm
-daemon manages link keys and PIN codes for Bluetooth devices.
-It opens a raw HCI socket and listens for the following HCI events.
-.Pp
-.Bl -tag -width XXXX -compact
-.It Dv Link_Key_Request
-.Nm
-scans the
-.Pa /var/db/bthcid.keys
-file for a cached link key matching the remote device BD_ADDR and, if
-found, the
-.Dv Link_Key_Request_Reply
-will be sent back to the device, otherwise the
-.Dv Link_Key_Request_Negative_Reply
-will be sent.
-.Pp
-.It Dv Link_Key_Notification
-When a new link key is created by the device, it will be cached for future
-use in the
-.Pa /var/db/bthcid.keys
-link keys file, which will be created if it does not already exist.
-.Pp
-.It Dv PIN_Code_Request
-The
-.Nm
-daemon checks its PIN cache for a matching remote device entry.
-If no PIN is found, the
-.Nm
-daemon will send a message to any PIN clients that have
-registered, with the device details and a timeout value.
-When no clients are available or the timeout has expired,
-.Nm
-will send a
-.Dv PIN_Code_Request_Negative_Reply
-back to the device.
-When a PIN is found, or if a client responds within the timeout period, a
-.Dv PIN_Code_Request_Reply
-will be sent back to the device.
-.Pp
-PINs received from clients will be cached for 5 minutes until used, and may be added
-to the cache prior to pairing with the
-.Xr btpin 1
-utility.
-.El
-.Pp
-The command line options are as follows:
-.Bl -tag -width XXXX
-.It Fl d Ar device
-Specify the local Bluetooth device address.
-The default is BDADDR_ANY.
-.It Fl f
-Run in foreground (do not detach).
-.It Fl h
-Display usage message and exit.
-.It Fl m
-Specify the file mode access bits for the PIN client socket.
-The default is to allow readwrite access to user and group (0660).
-.It Fl n
-Do not listen for PIN clients.
-.It Fl s Ar socket_name
-Specify the socket name to listen on for PIN clients.
-The default path is
-.Pa /var/run/bthcid .
-.El
-.Sh FILES
-.Bl -tag -compact -width ".Pa /var/run/bthcid.pid"
-.It Pa /var/db/bthcid.keys
-.It Pa /var/run/bthcid
-.It Pa /var/run/bthcid.pid
-.El
-.Sh SEE ALSO
-.Xr btpin 1 ,
-.Xr bluetooth 4 ,
-.Xr btconfig 8
-.Sh HISTORY
-The
-.Nm
-daemon first appeared in
-.Fx 5.3
-as
-.Ic hcsecd .
-It was ported to
-.Nx 4.0
-with its present name and extended to support PIN clients by
-.An Iain Hibbert
-under the sponsorship of Itronix, Inc.
-.Sh AUTHORS
-.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
-.An Iain Hibbert
-.Sh BUGS
-The only way to make the
-.Nm
-daemon forget a link key is to edit the
-.Pa /var/db/bthcid.keys
-file by hand.
-.Pp
-The only way to specify link keys (useful when multiple operating
-systems are used on the same hardware), is to edit the
-.Pa /var/db/bthcid.keys
-file by hand.
diff --git a/usr.sbin/bthcid/bthcid.c b/usr.sbin/bthcid/bthcid.c
deleted file mode 100644
index 32a475fc3f..0000000000
--- a/usr.sbin/bthcid/bthcid.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/* $NetBSD: bthcid.c,v 1.3 2007/01/25 20:33:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/bthcid/bthcid.c,v 1.1 2008/01/30 14:10:19 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/param.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/time.h>
-#include <bluetooth.h>
-#include <err.h>
-#include <errno.h>
-#include <libutil.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "bthcid.h"
-
-const	char	*socket_name = BTHCID_SOCKET_NAME;
-	int	 detach = 1;
-
-int	hci_kq;
-
-static void	process_signal(int);
-static void	usage(void);
-
-int
-main(int argc, char *argv[])
-{
-	bdaddr_t	bdaddr;
-	int		ch, hci_fd, control_fd;
-	mode_t		mode;
-	struct kevent	change;
-	struct timespec	timeout = { 0, 0 };
-	struct pidfh	*pfh = NULL;
-	const char	*pidfile = NULL;
-
-	bdaddr_copy(&bdaddr, BDADDR_ANY);
-	mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
-
-	while ((ch = getopt(argc, argv, "d:fm:ns:h")) != -1) {
-		switch (ch) {
-		case 'd':
-			if (!bt_devaddr(optarg, &bdaddr))
-				err(EXIT_FAILURE, "%s", optarg);
-			break;
-
-		case 'f':
-			detach = 0;
-			break;
-
-		case 'm':
-			mode = atoi(optarg);
-			break;
-
-		case 'n':
-			socket_name = NULL;
-			break;
-
-		case 's':
-			socket_name = optarg;
-			break;
-
-		case 'h':
-		default:
-			usage();
-			/* NOT REACHED */
-		}
-	}
-
-	if (getuid() != 0)
-		errx(EXIT_FAILURE,
-		    "** ERROR: You should run %s as privileged user!",
-		    getprogname());
-
-	if (detach)
-		if (daemon(0, 0) < 0)
-			err(EXIT_FAILURE, "Could not daemon()ize");
-
-	openlog(getprogname(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON);
-
-	if ((hci_kq = kqueue()) == -1) {
-		syslog(LOG_ERR, "could not create kqueue");
-		exit(EXIT_FAILURE);
-	}
-
-	EV_SET(&change, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
-	kevent(hci_kq, &change, 1, NULL, 0, &timeout);
-	EV_SET(&change, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
-	kevent(hci_kq, &change, 1, NULL, 0, &timeout);
-	EV_SET(&change, SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
-	kevent(hci_kq, &change, 1, NULL, 0, &timeout);
-
-	if ((hci_fd = init_hci(&bdaddr)) < 0) {
-		syslog(LOG_ERR, "init_hci(%s)", bt_ntoa(&bdaddr, NULL));
-		exit(EXIT_FAILURE);
-	}
-
-	if ((control_fd = init_control(socket_name, mode)) < 0) {
-		syslog(LOG_ERR, "init_control(%s)", socket_name);
-		exit(EXIT_FAILURE);
-	}
-
-	if (detach) {
-		pfh = pidfile_open(pidfile, 600, NULL);
-		if (pfh == NULL) {
-			syslog(LOG_ERR, "Could not create PID file: %m");
-			exit(EXIT_FAILURE);
-		}
-		pidfile_write(pfh);
-	}
-
-	read_config_file();
-	read_keys_file();
-
-	for ( ; ; ) {
-		int i, nevents;
-		struct kevent events[BTHCID_KQ_EVENTS], *event;
-
-		nevents = kevent(hci_kq, NULL, 0, &events[0], BTHCID_KQ_EVENTS, NULL);
-		if (nevents == -1) {
-			syslog(LOG_ERR, "kevent failure");
-			exit(EXIT_FAILURE);
-		}
-
-		for (i = 0; i < nevents; ++i) {
-			event = &events[i];
-
-			if (event->filter == EVFILT_SIGNAL) {
-				process_signal(event->ident);
-				continue;
-			}
-
-			if (event->filter == EVFILT_TIMER) {
-				process_item(event->udata);
-				continue;
-			}
-
-			if (event->ident == (u_int)control_fd) {
-				process_control(event->ident);
-				continue;
-			} else if (event->ident == (u_int)hci_fd) {
-				process_hci(event->ident);
-				continue;
-			} else if (event->udata != NULL) {
-				process_client(event->ident, event->udata);
-				continue;
-			}
-
-			syslog(LOG_DEBUG, "Unknown event for descriptor %d",
-			    (int)event->ident);
-		}
-	}
-
-	/* NOTREACHED */
-	/* gcc fodder */
-	exit(EXIT_FAILURE);
-}
-
-static void
-process_signal(int s)
-{
-	if (s == SIGHUP) {
-		syslog(LOG_DEBUG, "Got SIGHUP (%d). Dumping and rereading config", s);
-		dump_keys_file();
-		read_config_file();
-		read_keys_file();		
-		return;
-	}
-	
-
-
-	syslog(LOG_DEBUG, "Exiting on signal %d", s);
-
-	if (socket_name)
-		unlink(socket_name);
-
-	clean_config();
-	closelog();
-	exit(EXIT_FAILURE);
-
-}
-
-/* Display usage and exit */
-static void
-usage(void)
-{
-
-	fprintf(stderr,
-	    "Usage: %s [-fhn] [-c config] [-d devaddr] [-m mode] [-s path]\n"
-	    "Where:\n"
-	    "\t-c config   specify config filename\n"
-	    "\t-d device   specify device address\n"
-	    "\t-f          run in foreground\n"
-	    "\t-m mode     specify socket permissions\n"
-	    "\t-n          do not listen for clients\n"
-	    "\t-s path     specify client socket pathname\n"
-	    "\t-h          display this message\n",
-	    getprogname());
-
-	exit(EXIT_FAILURE);
-}
diff --git a/usr.sbin/bthcid/bthcid.h b/usr.sbin/bthcid/bthcid.h
deleted file mode 100644
index 6e7cc7939a..0000000000
--- a/usr.sbin/bthcid/bthcid.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* $NetBSD: bthcid.h,v 1.3 2006/09/26 19:18:19 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
-
-#ifndef _BTHCID_H_
-#define _BTHCID_H_	1
-
-#include <sys/queue.h>
-
-/* config.c */
-uint8_t		*lookup_key		(bdaddr_t *, bdaddr_t *);
-void		 save_key		(bdaddr_t *, bdaddr_t *, uint8_t *);
-void 		 create_dict(bdaddr_t *laddr, bdaddr_t *raddr, uint8_t * key);
-
-/* client.c */
-int		 init_control		(const char *, mode_t);
-int		 send_client_request	(bdaddr_t *, bdaddr_t *, int);
-uint8_t		*lookup_pin		(bdaddr_t *, bdaddr_t *);
-uint8_t		*lookup_pin_conf	(bdaddr_t *, bdaddr_t *);
-void		process_control		(int);
-void		process_client		(int, void *);
-void		process_item		(void *);
-
-/* hci.c */
-int		init_hci		(bdaddr_t *);
-void		process_hci		(int);
-int		send_pin_code_reply	(int, struct sockaddr_bt *, bdaddr_t *, uint8_t *);
-
-#define BTHCID_BUFFER_SIZE	512
-#define BTHCID_IDENT		"bthcid"
-#define BTHCID_PIDFILE		"/var/run/" BTHCID_IDENT ".pid"
-#define BTHCID_KEYSFILE		"/var/db/"  BTHCID_IDENT ".keys"
-#define BTHCID_KQ_EVENTS	64
-
-struct link_key
-{
-	bdaddr_t		 bdaddr; /* remote device BDADDR */
-	char			*name;   /* remote device name */
-	uint8_t			*key;    /* link key (or NULL if no key) */
-	char			*pin;    /* pin (or NULL if no pin) */
-	LIST_ENTRY(link_key)	 next;   /* link to the next */
-};
-typedef struct link_key		link_key_t;
-typedef struct link_key *	link_key_p;
-
-extern const char		*config_file;
-extern int			hci_kq;
-
-#ifdef __config_debug__
-void		dump_config	(void);
-#endif
-
-#ifndef bdaddr_p 
-#define bdaddr_p bdaddr_t *
-#endif
-
-void		read_config_file(void);
-void		clean_config	(void);
-link_key_p	get_key		(bdaddr_p bdaddr, int exact_match);
-
-int		read_keys_file  (void);
-int		dump_keys_file  (void);
-
-#endif	/* _BTHCID_H_ */
diff --git a/usr.sbin/bthcid/client.c b/usr.sbin/bthcid/client.c
deleted file mode 100644
index a184330ce4..0000000000
--- a/usr.sbin/bthcid/client.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/* $NetBSD: client.c,v 1.4 2006/09/29 20:06:11 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/bthcid/client.c,v 1.1 2008/01/30 14:10:19 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/ioctl.h>
-#include <sys/queue.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/time.h>
-#include <sys/un.h>
-#include <bluetooth.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "bthcid.h"
-
-/*
- * A client is anybody who connects to our control socket to
- * receive PIN requests.
- */
-struct client {
-	int			fd;		/* client descriptor */
-	LIST_ENTRY(client)	next;
-};
-
-/*
- * PIN cache items are made when we have sent a client pin
- * request. The event is used to expire the item.
- */
-struct item {
-	bdaddr_t	 laddr;			/* local device BDADDR */
-	bdaddr_t	 raddr;			/* remote device BDADDR */
-	uint8_t		 pin[HCI_PIN_SIZE];	/* PIN */
-	int		 hci;			/* HCI socket */
-	LIST_ENTRY(item) next;
-};
-
-static LIST_HEAD(,client)	client_list;
-static LIST_HEAD(,item)		item_list;
-
-#define PIN_REQUEST_TIMEOUT	30	/* Request is valid */
-#define PIN_TIMEOUT		300	/* PIN is valid */
-
-int
-init_control(const char *name, mode_t mode)
-{
-	struct sockaddr_un	un;
-	struct kevent		change;
-	struct timespec		timeout = { 0, 0 };
-	int			ctl;
-
-	LIST_INIT(&client_list);
-	LIST_INIT(&item_list);
-
-	if (name == NULL)
-		return 0;
-
-	if (unlink(name) < 0 && errno != ENOENT)
-		return -1;
-
-	ctl = socket(PF_LOCAL, SOCK_STREAM, 0);
-	if (ctl < 0)
-		return -1;
-
-	memset(&un, 0, sizeof(un));
-	un.sun_len = sizeof(un);
-	un.sun_family = AF_LOCAL;
-	strlcpy(un.sun_path, name, sizeof(un.sun_path));
-	if (bind(ctl, (struct sockaddr *)&un, sizeof(un)) < 0) {
-		close(ctl);
-		return -1;
-	}
-
-	if (chmod(name, mode) < 0) {
-		close(ctl);
-		unlink(name);
-		return -1;
-	}
-
-	if (listen(ctl, 10) < 0) {
-		close(ctl);
-		unlink(name);
-		return -1;
-	}
-
-	EV_SET(&change, ctl, EVFILT_READ, EV_ADD, 0, 0, NULL);
-	if (kevent(hci_kq, &change, 1, NULL, 0, &timeout) == -1) {
-		close(ctl);
-		unlink(name);
-		return -1;
-	}
-
-	return ctl;
-}
-
-/* Process control socket event */
-void
-process_control(int sock)
-{
-	struct sockaddr_un	un;
-	socklen_t		n;
-	struct kevent		change;
-	struct timespec		timeout = { 0, 0 };
-	int			fd;
-	struct client		*cl;
-
-	n = sizeof(un);
-	fd = accept(sock, (struct sockaddr *)&un, &n);
-	if (fd < 0) {
-		syslog(LOG_ERR, "Could not accept PIN client connection");
-		return;
-	}
-
-	n = 1;
-	if (ioctl(fd, FIONBIO, &n) < 0) {
-		syslog(LOG_ERR, "Could not set non blocking IO for client");
-		close(fd);
-		return;
-	}
-
-	cl = malloc(sizeof(struct client));
-	if (cl == NULL) {
-		syslog(LOG_ERR, "Could not malloc client");
-		close(fd);
-		return;
-	}
-
-	memset(cl, 0, sizeof(struct client));
-	cl->fd = fd;
-
-	EV_SET(&change, cl->fd, EVFILT_READ, EV_ADD, 0, 0, cl);
-	if (kevent(hci_kq, &change, 1, NULL, 0, &timeout) == -1) {
-		syslog(LOG_ERR, "Could not add client event");
-		free(cl);
-		close(fd);
-		return;
-	}
-
-	syslog(LOG_DEBUG, "New Client");
-	LIST_INSERT_HEAD(&client_list, cl, next);
-}
-
-/* Process client response packet */
-void
-process_client(int sock, void *arg)
-{
-	bthcid_pin_response_t	 rp;
-	struct sockaddr_bt	 sa;
-	struct client		*cl = arg;
-	struct item		*item;
-	struct kevent		change;
-	struct timespec		timeout = { 0, 0 };
-	int			 n;
-
-	n = recv(sock, &rp, sizeof(rp), 0);
-	if (n != sizeof(rp)) {
-		if (n != 0)
-			syslog(LOG_ERR, "Bad Client");
-
-		close(sock);
-		LIST_REMOVE(cl, next);
-		free(cl);
-
-		syslog(LOG_DEBUG, "Client Closed");
-		return;
-	}
-
-	syslog(LOG_DEBUG, "Received PIN for %s", bt_ntoa(&rp.raddr, NULL));
-
-	LIST_FOREACH(item, &item_list, next) {
-		if (bdaddr_same(&rp.laddr, &item->laddr) == 0
-		    || bdaddr_same(&rp.raddr, &item->raddr) == 0)
-			continue;
-
-		EV_SET(&change, sock, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
-		kevent(hci_kq, &change, 1, NULL, 0, &timeout);
-		if (item->hci != -1) {
-			memset(&sa, 0, sizeof(sa));
-			sa.bt_len = sizeof(sa);
-			sa.bt_family = AF_BLUETOOTH;
-			bdaddr_copy(&sa.bt_bdaddr, &item->laddr);
-
-			send_pin_code_reply(item->hci, &sa, &item->raddr, rp.pin);
-			LIST_REMOVE(item, next);
-			free(item);
-			return;
-		}
-		goto newpin;
-	}
-
-	item = malloc(sizeof(struct item));
-	if (item == NULL) {
-		syslog(LOG_ERR, "Item allocation failed");
-		return;
-	}
-
-	memset(item, 0, sizeof(struct item));
-	bdaddr_copy(&item->laddr, &rp.laddr);
-	bdaddr_copy(&item->raddr, &rp.raddr);
-	LIST_INSERT_HEAD(&item_list, item, next);
-
-newpin:
-	syslog(LOG_DEBUG, "Caching PIN for %s", bt_ntoa(&rp.raddr, NULL));
-
-	memcpy(item->pin, rp.pin, HCI_PIN_SIZE);
-	item->hci = -1;
-
-	EV_SET(&change, sock, EVFILT_TIMER, EV_ADD, 0, PIN_TIMEOUT * 1000, NULL);
-	if (kevent(hci_kq, &change, 1, NULL, 0, &timeout) == -1) {
-		syslog(LOG_ERR, "Cannot add event timer for item");
-		LIST_REMOVE(item, next);
-		free(item);
-	}
-}
-
-/* Send PIN request to client */
-int
-send_client_request(bdaddr_t *laddr, bdaddr_t *raddr, int hci)
-{
-	bthcid_pin_request_t	 cp;
-	struct client		*cl;
-	struct item		*item;
-	struct kevent		change;
-	struct timespec		timeout = { 0, 0 };
-	int			n = 0;
-
-	memset(&cp, 0, sizeof(cp));
-	bdaddr_copy(&cp.laddr, laddr);
-	bdaddr_copy(&cp.raddr, raddr);
-	cp.time = PIN_REQUEST_TIMEOUT;
-
-	LIST_FOREACH(cl, &client_list, next) {
-		if (send(cl->fd, &cp, sizeof(cp), 0) != sizeof(cp))
-			syslog(LOG_ERR, "send PIN request failed");
-		else
-			n++;
-	}
-
-	if (n == 0)
-		return 0;
-
-	syslog(LOG_DEBUG, "Sent PIN requests to %d client%s.",
-				n, (n == 1 ? "" : "s"));
-
-	item = malloc(sizeof(struct item));
-	if (item == NULL) {
-		syslog(LOG_ERR, "Cannot allocate PIN request item");
-		return 0;
-	}
-
-	memset(item, 0, sizeof(struct item));
-	bdaddr_copy(&item->laddr, laddr);
-	bdaddr_copy(&item->raddr, raddr);
-	item->hci = hci;
-	EV_SET(&change, item->hci, EVFILT_TIMER, EV_ADD, 0, cp.time * 1000, item);
-	if (kevent(hci_kq, &change, 1, NULL, 0, &timeout) == -1) {
-		syslog(LOG_ERR, "Cannot add request timer");
-		free(item);
-		return 0;
-	}
-
-	LIST_INSERT_HEAD(&item_list, item, next);
-	return 1;
-}
-
-/* Process item event (by expiring it) */
-void
-process_item(void *arg)
-{
-	struct item *item = arg;
-	struct kevent change;
-	struct timespec timeout = { 0, 0 };
-
-	syslog(LOG_DEBUG, "PIN for %s expired", bt_ntoa(&item->raddr, NULL));
-	LIST_REMOVE(item, next);
-	EV_SET(&change, item->hci, EVFILT_TIMER, EV_DELETE, 0, 0, 0);
-	kevent(hci_kq, &change, 1, NULL, 0, &timeout);
-	free(item);
-}
-
-/* lookup PIN in item cache */
-uint8_t *
-lookup_pin(bdaddr_t *laddr, bdaddr_t *raddr)
-{
-	static uint8_t pin[HCI_PIN_SIZE];
-	struct item *item;
-	struct kevent change;
-	struct timespec timeout = { 0, 0 };
-
-	LIST_FOREACH(item, &item_list, next) {
-		if (bdaddr_same(raddr, &item->raddr) == 0)
-			continue;
-
-		if (bdaddr_same(laddr, &item->laddr) == 0
-		    && bdaddr_any(&item->laddr) == 0)
-			continue;
-
-		if (item->hci >= 0)
-			break;
-
-		syslog(LOG_DEBUG, "Matched PIN from cache");
-		memcpy(pin, item->pin, sizeof(pin));
-
-		LIST_REMOVE(item, next);
-		EV_SET(&change, item->hci, EVFILT_TIMER, EV_DELETE, 0, 0, 0);
-		kevent(hci_kq, &change, 1, NULL, 0, &timeout);
-		free(item);
-
-		return pin;
-	}
-
-	return NULL;
-}
diff --git a/usr.sbin/bthcid/config.c b/usr.sbin/bthcid/config.c
deleted file mode 100644
index 77462eca70..0000000000
--- a/usr.sbin/bthcid/config.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/* $NetBSD: config.c,v 1.4 2007/01/25 20:33:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/bthcid/config.c,v 1.1 2008/01/30 14:10:19 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/time.h>
-#include <bluetooth.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "bthcid.h"
-
-#if 0
-static const char *key_file = "/var/db/bthcid.keys";
-static const char *new_key_file = "/var/db/bthcid.keys.new";
-#endif
-
-/*
- * Look up key in keys file. We store a dictionary for each
- * remote address, and inside that we have a data object for
- * each local address containing the key.
- */
-uint8_t *
-lookup_key(bdaddr_t *laddr, bdaddr_t *raddr)
-{
-	link_key_p	key = NULL;
-
-	syslog(LOG_DEBUG, "Got Link_Key_Request event from '%s', " \
-			"remote bdaddr %s", bt_ntoa(laddr, NULL),
-			bt_ntoa(raddr, NULL));
-
-	if ((key = get_key(raddr, 0)) != NULL) {
-		syslog(LOG_DEBUG, "Found matching entry, " \
-				"remote bdaddr %s, name '%s', link key %s",
-				bt_ntoa(&key->bdaddr, NULL),
-				(key->name != NULL)? key->name : "No name",
-				(key->key != NULL)? "exists" : "doesn't exist");
-		return key->key;
-	}
-
-	syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s",
-			bt_ntoa(raddr, NULL));
-	return NULL;
-}
-
-/*
- * Look up pin in keys file. We store a dictionary for each
- * remote address, and inside that we have a data object for
- * each local address containing the pin.
- */
-uint8_t *
-lookup_pin_conf(bdaddr_t *laddr, bdaddr_t *raddr)
-{
-	link_key_p	key = NULL;
-
-	syslog(LOG_DEBUG, "Got Link_Pin_Request event from '%s', " \
-			"remote bdaddr %s", bt_ntoa(laddr, NULL),
-			bt_ntoa(raddr, NULL));
-
-	if ((key = get_key(raddr, 0)) != NULL) {
-		syslog(LOG_DEBUG, "Found matching entry, " \
-				"remote bdaddr %s, name '%s', pin %s",
-				bt_ntoa(&key->bdaddr, NULL),
-				(key->name != NULL)? key->name : "No name",
-				(key->pin != NULL)? "exists" : "doesn't exist");
-		return key->pin;
-	}
-
-	syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s",
-			bt_ntoa(raddr, NULL));
-	return NULL;
-}
-
-
-void
-save_key(bdaddr_t *laddr, bdaddr_t *raddr, uint8_t * key)
-{
-	link_key_p	lkey = NULL;
-
-	syslog(LOG_DEBUG, "Got Link_Key_Notification event from '%s', " \
-			"remote bdaddr %s", bt_ntoa(laddr, NULL),
-			bt_ntoa(raddr, NULL));
-
-	if ((lkey = get_key(raddr, 1)) == NULL) {
-		syslog(LOG_ERR, "Could not find entry for remote bdaddr %s",
-				bt_ntoa(raddr, NULL));
-		return;
-	}
-	
-	syslog(LOG_DEBUG, "Updating link key for the entry, " \
-			"remote bdaddr %s, name '%s', link key %s",
-			bt_ntoa(&lkey->bdaddr, NULL),
-			(lkey->name != NULL)? lkey->name : "No name",
-			(lkey->key != NULL)? "exists" : "doesn't exist");
-
-	if (lkey->key == NULL) {
-		lkey->key = (uint8_t *) malloc(HCI_KEY_SIZE);
-		if (lkey->key == NULL) {
-			syslog(LOG_ERR, "Could not allocate link key");
-			exit(1);
-		}
-	}
-
-	memcpy(lkey->key, key, HCI_KEY_SIZE);
-
-	dump_keys_file();
-	read_config_file();
-	read_keys_file();
-	
-	return;
-}
-
diff --git a/usr.sbin/bthcid/hci.c b/usr.sbin/bthcid/hci.c
deleted file mode 100644
index 8bc7be78bf..0000000000
--- a/usr.sbin/bthcid/hci.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/* $NetBSD: hci.c,v 1.2 2007/01/25 20:33:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/bthcid/hci.c,v 1.2 2008/02/02 09:21:24 swildner Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
- * 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.
- */
-
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <sys/event.h>
-#include <sys/types.h>
-#include <bluetooth.h>
-#include <errno.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "bthcid.h"
-
-static int process_pin_code_request_event
-		(int, struct sockaddr_bt *, bdaddr_t *);
-static int process_link_key_request_event
-		(int, struct sockaddr_bt *, bdaddr_t *);
-static int process_link_key_notification_event
-		(int, struct sockaddr_bt *, hci_link_key_notification_ep *);
-
-static int send_link_key_reply
-		(int, struct sockaddr_bt *, bdaddr_t *, uint8_t *);
-static int send_hci_cmd
-		(int, struct sockaddr_bt *, uint16_t, size_t, void *);
-
-static char dev_name[HCI_DEVNAME_SIZE];
-
-/* Initialise HCI Events */
-int
-init_hci(bdaddr_t *bdaddr)
-{
-	struct sockaddr_bt	sa;
-	struct hci_filter	filter;
-	struct kevent		change;
-	struct timespec		timeout = { 0, 0 };
-	int			hci;
-
-	hci = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
-	if (hci < 0)
-		return -1;
-
-	memset(&sa, 0, sizeof(sa));
-	sa.bt_len = sizeof(sa);
-	sa.bt_family = AF_BLUETOOTH;
-	bdaddr_copy(&sa.bt_bdaddr, bdaddr);
-	if (bind(hci, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
-		close(hci);
-		return -1;
-	}
-
-	memset(&filter, 0, sizeof(filter));
-	hci_filter_set(HCI_EVENT_PIN_CODE_REQ, &filter);
-	hci_filter_set(HCI_EVENT_LINK_KEY_REQ, &filter);
-	hci_filter_set(HCI_EVENT_LINK_KEY_NOTIFICATION, &filter);
-
-	if (setsockopt(hci, BTPROTO_HCI, SO_HCI_EVT_FILTER,
-			(const void *)&filter, sizeof(filter)) < 0) {
-		close(hci);
-		return -1;
-	}
-
-	EV_SET(&change, hci, EVFILT_READ, EV_ADD, 0, 0, NULL);
-	if (kevent(hci_kq, &change, 1, NULL, 0, &timeout) == -1) {
-		close(hci);
-		return -1;
-	}
-
-	return hci;
-}
-
-/* Process an HCI event */
-void
-process_hci(int sock)
-{
-	char			 buffer[HCI_EVENT_PKT_SIZE];
-	hci_event_hdr_t		*event = (hci_event_hdr_t *)buffer;
-	struct sockaddr_bt	 addr;
-	int			 n;
-	socklen_t		 size;
-
-	size = sizeof(addr);
-	n = recvfrom(sock, buffer, sizeof(buffer), 0,
-			(struct sockaddr *) &addr, &size);
-	if (n < 0) {
-		syslog(LOG_ERR, "Could not receive from HCI socket: %m");
-		return;
-	}
-
-	if (event->type != HCI_EVENT_PKT) {
-		syslog(LOG_ERR, "Received unexpected HCI packet, "
-				"type=%#x", event->type);
-
-		return;
-	}
-
-	if (!bt_devname(dev_name, &addr.bt_bdaddr))
-		strlcpy(dev_name, "unknown", sizeof(dev_name));
-
-	switch (event->event) {
-	case HCI_EVENT_PIN_CODE_REQ:
-		process_pin_code_request_event(sock, &addr,
-					    (bdaddr_t *)(event + 1));
-		break;
-
-	case HCI_EVENT_LINK_KEY_REQ:
-		process_link_key_request_event(sock, &addr,
-					    (bdaddr_t *)(event + 1));
-		break;
-
-	case HCI_EVENT_LINK_KEY_NOTIFICATION:
-		process_link_key_notification_event(sock, &addr,
-			(hci_link_key_notification_ep *)(event + 1));
-		break;
-
-	default:
-		syslog(LOG_ERR, "Received unexpected HCI event, "
-				"event=%#x", event->event);
-		break;
-	}
-
-	return;
-}
-
-/* Process PIN_Code_Request event */
-static int
-process_pin_code_request_event(int sock, struct sockaddr_bt *addr,
-		bdaddr_t *bdaddr)
-{
-	/* TODO: Add search pin in config file */
-
-	uint8_t	*pin;
-	uint8_t	*pin2;
-
-	syslog(LOG_DEBUG, "Got PIN_Code_Request event from %s, "
-			  "remote bdaddr %s",
-			  dev_name,
-			  bt_ntoa(bdaddr, NULL));
-
-	pin = lookup_pin(&addr->bt_bdaddr, bdaddr);
-	if (pin != NULL)
-		return send_pin_code_reply(sock, addr, bdaddr, pin);
-	
-	pin2 = lookup_pin_conf(&addr->bt_bdaddr, bdaddr);
-	if (pin2 != NULL) {
-		return send_pin_code_reply(sock, addr, bdaddr, pin2);
-	}
-	
-	if (send_client_request(&addr->bt_bdaddr, bdaddr, sock) == 0)
-		return send_pin_code_reply(sock, addr, bdaddr, NULL);
-
-	return 0;
-}
-
-/* Process Link_Key_Request event */
-static int
-process_link_key_request_event(int sock, struct sockaddr_bt *addr,
-		bdaddr_t *bdaddr)
-{
-	uint8_t		*key;
-
-	syslog(LOG_DEBUG,
-		"Got Link_Key_Request event from %s, remote bdaddr %s",
-		dev_name, bt_ntoa(bdaddr, NULL));
-
-	key = lookup_key(&addr->bt_bdaddr, bdaddr);
-
-	if (key != NULL) {
-		syslog(LOG_DEBUG, "Found Key, remote bdaddr %s",
-				bt_ntoa(bdaddr, NULL));
-
-		return send_link_key_reply(sock, addr, bdaddr, key);
-	}
-
-	syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s",
-			bt_ntoa(bdaddr, NULL));
-
-	return send_link_key_reply(sock, addr, bdaddr, NULL);
-}
-
-/* Send PIN_Code_[Negative]_Reply */
-int
-send_pin_code_reply(int sock, struct sockaddr_bt *addr,
-	bdaddr_t *bdaddr, uint8_t *pin)
-{
-	int	n;
-
-	if (pin != NULL) {
-		hci_pin_code_rep_cp	 cp;
-
-		syslog(LOG_DEBUG, "Sending PIN_Code_Reply to %s "
-				  "for remote bdaddr %s",
-				  dev_name,
-				  bt_ntoa(bdaddr, NULL));
-
-		bdaddr_copy(&cp.bdaddr, bdaddr);
-		memcpy(cp.pin, pin, HCI_PIN_SIZE);
-
-		n = HCI_PIN_SIZE;
-		while (n > 0 && pin[n - 1] == 0)
-			n--;
-		cp.pin_size = n;
-
-		n = send_hci_cmd(sock, addr,
-				HCI_CMD_PIN_CODE_REP, sizeof(cp), &cp);
-
-	} else {
-		syslog(LOG_DEBUG, "Sending PIN_Code_Negative_Reply to %s "
-				  "for remote bdaddr %s",
-				  dev_name,
-				  bt_ntoa(bdaddr, NULL));
-
-		n = send_hci_cmd(sock, addr, HCI_CMD_PIN_CODE_NEG_REP,
-					sizeof(bdaddr_t), bdaddr);
-	}
-
-	if (n < 0) {
-		syslog(LOG_ERR, "Could not send PIN code reply to %s "
-				"for remote bdaddr %s: %m",
-				dev_name,
-				bt_ntoa(bdaddr, NULL));
-
-		return -1;
-	}
-
-	return 0;
-}
-
-/* Send Link_Key_[Negative]_Reply */
-static int
-send_link_key_reply(int sock, struct sockaddr_bt *addr,
-		bdaddr_t *bdaddr, uint8_t *key)
-{
-	int	n;
-
-	if (key != NULL) {
-		hci_link_key_rep_cp	cp;
-
-		bdaddr_copy(&cp.bdaddr, bdaddr);
-		memcpy(&cp.key, key, sizeof(cp.key));
-
-		syslog(LOG_DEBUG, "Sending Link_Key_Reply to %s "
-				"for remote bdaddr %s",
-				dev_name, bt_ntoa(bdaddr, NULL));
-
-		n = send_hci_cmd(sock, addr, HCI_CMD_LINK_KEY_REP, sizeof(cp), &cp);
-	} else {
-		hci_link_key_neg_rep_cp	cp;
-
-		bdaddr_copy(&cp.bdaddr, bdaddr);
-
-		syslog(LOG_DEBUG, "Sending Link_Key_Negative_Reply to %s "
-				"for remote bdaddr %s",
-				dev_name, bt_ntoa(bdaddr, NULL));
-
-		n = send_hci_cmd(sock, addr, HCI_CMD_LINK_KEY_NEG_REP, sizeof(cp), &cp);
-	}
-
-	if (n < 0) {
-		syslog(LOG_ERR, "Could not send link key reply to %s "
-				"for remote bdaddr %s: %m",
-				dev_name, bt_ntoa(bdaddr, NULL));
-		return -1;
-	}
-
-	return 0;
-}
-
-/* Process Link_Key_Notification event */
-static int
-process_link_key_notification_event(int sock __unused, struct sockaddr_bt *addr,
-		hci_link_key_notification_ep *ep)
-{
-
-	syslog(LOG_DEBUG, "Got Link_Key_Notification event from %s, "
-			"remote bdaddr %s",
-			dev_name,
-			bt_ntoa(&ep->bdaddr, NULL));
-
-	save_key(&addr->bt_bdaddr, &ep->bdaddr, ep->key);
-	return 0;
-}
-
-/* Send HCI Command Packet to socket */
-static int
-send_hci_cmd(int sock, struct sockaddr_bt *sa, uint16_t opcode, size_t len, void *buf)
-{
-	char msg[HCI_CMD_PKT_SIZE];
-	hci_cmd_hdr_t *h = (hci_cmd_hdr_t *)msg;
-
-	h->type = HCI_CMD_PKT;
-	h->opcode = htole16(opcode);
-	h->length = len;
-
-	if (len > 0)
-		memcpy(msg + sizeof(hci_cmd_hdr_t), buf, len);
-
-	return sendto(sock, msg, sizeof(hci_cmd_hdr_t) + len, 0,
-			(struct sockaddr *)sa, sizeof(*sa));
-}
diff --git a/usr.sbin/bthidcontrol/Makefile b/usr.sbin/bthidcontrol/Makefile
new file mode 100644
index 0000000000..fa25b463e9
--- /dev/null
+++ b/usr.sbin/bthidcontrol/Makefile
@@ -0,0 +1,15 @@
+# $Id: Makefile,v 1.2 2004/02/13 21:44:41 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/bthidcontrol/Makefile 128080 2004-04-10 00:18:00Z emax $
+
+.PATH:	${.CURDIR}/../bthidd
+
+PROG=		bthidcontrol
+MAN=		bthidcontrol.8
+SRCS=		bthidcontrol.c hid.c lexer.l  parser.y sdp.c
+WARNS?=		1
+CFLAGS+=	-DBTHIDCONTROL=1 -I${.CURDIR}/../bthidd
+
+DPADD=		${LIBBLUETOOTH} ${LIBSDP} ${LIBUSBHID}
+LDADD=		-lbluetooth -lsdp -lusbhid
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bthidcontrol/bthidcontrol.8 b/usr.sbin/bthidcontrol/bthidcontrol.8
new file mode 100644
index 0000000000..35d5de1bb7
--- /dev/null
+++ b/usr.sbin/bthidcontrol/bthidcontrol.8
@@ -0,0 +1,102 @@
+.\" Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: bthidcontrol.8,v 1.1 2004/02/13 21:44:41 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd October 30, 2006
+.Dt BTHIDCONTROL 8
+.Os
+.Sh NAME
+.Nm bthidcontrol
+.Nd Bluetooth HID control utility
+.Sh SYNOPSIS
+.Nm
+.Fl h
+.Nm
+.Op Fl a Ar BD_ADDR
+.Op Fl c Ar file
+.Op Fl H Ar file
+.Op Fl v
+.Ar command
+.Sh DESCRIPTION
+The
+.Nm
+utility can be used to query remote Bluetooth HID devices, dump HID descriptors
+in human readable form and perform simple manipulations on the Bluetooth HID
+daemon configuration files.
+.Pp
+The
+.Nm
+utility will print results to the standard output and error messages to the
+standard error.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar BD_ADDR
+Specify BD_ADDR for the HID device.
+Example:
+.Fl a Li 00:01:02:03:04:05 .
+.It Fl c Ar file
+Specify path to the Bluetooth HID daemon configuration file.
+The default path is
+.Pa /etc/bluetooth/bthidd.conf .
+.It Fl H Ar file
+Specify path to the Bluetooth HID daemon known HIDs file.
+The default path is
+.Pa /var/db/bthidd.hids .
+.It Fl h
+Display usage message and exit.
+.It Fl v
+Be verbose and show items that are being used for padding.
+.It Ar command
+One of the supported commands (see below).
+Special command
+.Cm help
+can be used to obtain the list of all supported commands.
+To get more information about specific command use
+.Cm help Ar command .
+.El
+.Sh COMMANDS
+The currently supported node commands in
+.Nm
+are:
+.Pp
+.Bl -tag -width "Forget" -offset indent -compact
+.It Cm Query
+.It Cm Dump
+.It Cm Known
+.It Cm Forget
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/bluetooth/bthidd.conf" -compact
+.It Pa /etc/bluetooth/bthidd.conf
+.It Pa /var/db/bthidd.hids
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr bthidd 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
diff --git a/usr.sbin/bthidcontrol/bthidcontrol.c b/usr.sbin/bthidcontrol/bthidcontrol.c
new file mode 100644
index 0000000000..8ed7503101
--- /dev/null
+++ b/usr.sbin/bthidcontrol/bthidcontrol.c
@@ -0,0 +1,215 @@
+/*
+ * bthidcontrol.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: bthidcontrol.c,v 1.2 2004/02/13 21:44:41 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.c 163811 2006-10-31 00:26:58Z markus $
+ */
+
+#include <sys/queue.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <usbhid.h>
+#include "bthid_config.h"
+#include "bthidcontrol.h"
+
+static int do_bthid_command(bdaddr_p bdaddr, int argc, char **argv);
+static struct bthid_command * find_bthid_command(char const *command, struct bthid_command *category);
+static void print_bthid_command(struct bthid_command *category);
+static void usage(void);
+
+int32_t hid_sdp_query(bdaddr_t const *local, bdaddr_t const *remote, int32_t *error);
+
+uint32_t verbose = 0;
+
+/*
+ * bthidcontrol
+ */
+
+int
+main(int argc, char *argv[])
+{
+	bdaddr_t	bdaddr;
+	int		opt;
+
+	hid_init(NULL);
+	memcpy(&bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr));
+
+	while ((opt = getopt(argc, argv, "a:c:H:hv")) != -1) {
+		switch (opt) {
+		case 'a': /* bdaddr */
+			if (!bt_aton(optarg, &bdaddr)) {
+				struct hostent  *he = NULL;
+
+				if ((he = bt_gethostbyname(optarg)) == NULL)
+					errx(1, "%s: %s", optarg, hstrerror(h_errno));
+
+				memcpy(&bdaddr, he->h_addr, sizeof(bdaddr));
+			}
+			break;
+
+		case 'c': /* config file */
+			config_file = optarg;
+			break;
+
+		case 'H': /* HIDs file */
+			hids_file = optarg;
+			break;
+
+		case 'v': /* verbose */
+			verbose++;
+			break;
+
+		case 'h':
+		default:
+			usage();
+			/* NOT REACHED */
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (*argv == NULL)
+		usage();
+
+	return (do_bthid_command(&bdaddr, argc, argv));
+} /* main */
+
+/* Execute commands */
+static int
+do_bthid_command(bdaddr_p bdaddr, int argc, char **argv)
+{
+	char			*cmd = argv[0];
+	struct bthid_command	*c = NULL;
+	int			 e, help;
+
+	help = 0;
+	if (strcasecmp(cmd, "help") == 0) {
+		argc --;
+		argv ++;
+
+		if (argc <= 0) {
+			fprintf(stdout, "Supported commands:\n");
+			print_bthid_command(sdp_commands);
+			print_bthid_command(hid_commands);
+			fprintf(stdout, "\nFor more information use " \
+					"'help command'\n");
+
+			return (OK);
+		}
+
+		help = 1;
+		cmd = argv[0];
+	}
+
+	c = find_bthid_command(cmd, sdp_commands); 
+	if (c == NULL)
+		c = find_bthid_command(cmd, hid_commands); 
+
+	if (c == NULL) {
+		fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
+		return (ERROR);
+	}
+
+	if (!help)
+		e = (c->handler)(bdaddr, -- argc, ++ argv);
+	else
+		e = USAGE;
+
+	switch (e) {
+	case OK:
+	case FAILED:
+		break;
+
+	case ERROR:
+		fprintf(stdout, "Could not execute command \"%s\". %s\n",
+				cmd, strerror(errno));
+		break;
+
+	case USAGE:
+		fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
+		break;
+
+	default: assert(0); break;
+	}
+
+	return (e);
+} /* do_bthid_command */
+
+/* Try to find command in specified category */
+static struct bthid_command *
+find_bthid_command(char const *command, struct bthid_command *category)
+{ 
+	struct bthid_command	*c = NULL;
+  
+	for (c = category; c->command != NULL; c++) {
+		char	*c_end = strchr(c->command, ' ');
+  
+		if (c_end != NULL) {
+			int	len = c_end - c->command;
+ 
+			if (strncasecmp(command, c->command, len) == 0)
+				return (c);
+		} else if (strcasecmp(command, c->command) == 0)
+				return (c);
+	}
+  
+	return (NULL);
+} /* find_bthid_command */
+
+/* Print commands in specified category */
+static void
+print_bthid_command(struct bthid_command *category)
+{
+	struct bthid_command	*c = NULL;
+ 
+	for (c = category; c->command != NULL; c++)
+		fprintf(stdout, "\t%s\n", c->command);
+} /* print_bthid_command */
+
+/* Usage */ 
+static void
+usage(void)
+{
+	fprintf(stderr,
+"Usage: bthidcontrol options command\n" \
+"Where options are:\n"
+"	-a bdaddr	specify bdaddr\n" \
+"	-c file		specify path to the bthidd config file\n" \
+"	-H file		specify path to the bthidd HIDs file\n" \
+"	-h		display usage and quit\n" \
+"	-v		be verbose\n" \
+"	command		one of the supported commands\n");
+	exit(255);
+} /* usage */
+
diff --git a/usr.sbin/bthidcontrol/bthidcontrol.h b/usr.sbin/bthidcontrol/bthidcontrol.h
new file mode 100644
index 0000000000..be9afdb6e2
--- /dev/null
+++ b/usr.sbin/bthidcontrol/bthidcontrol.h
@@ -0,0 +1,50 @@
+/*
+ * bthidcontrol.h
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: bthidcontrol.h,v 1.1 2004/02/12 23:25:51 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidcontrol/bthidcontrol.h 128080 2004-04-10 00:18:00Z emax $
+ */
+
+#ifndef __BTHIDCONTROL_H__
+#define __BTHIDCONTROL_H__
+
+#define OK			0	/* everything was OK */
+#define ERROR			1	/* could not execute command */
+#define FAILED			2	/* error was reported */
+#define USAGE			3	/* invalid parameters */
+
+struct bthid_command {
+	char const		*command;
+	char const		*description;
+	int			(*handler)(bdaddr_t *, int, char **);
+};
+
+extern struct bthid_command	hid_commands[];
+extern struct bthid_command	sdp_commands[];
+
+#endif /* __BTHIDCONTROL_H__ */
+
diff --git a/usr.sbin/bthidcontrol/hid.c b/usr.sbin/bthidcontrol/hid.c
new file mode 100644
index 0000000000..2d8fbaf8dc
--- /dev/null
+++ b/usr.sbin/bthidcontrol/hid.c
@@ -0,0 +1,214 @@
+/*
+ * hid.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: hid.c,v 1.3 2004/02/17 22:14:57 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidcontrol/hid.c 163811 2006-10-31 00:26:58Z markus $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usbhid.h>
+#include <stdio.h>
+#include <string.h>
+#include <usbhid.h>
+#include "bthid_config.h"
+#include "bthidcontrol.h"
+
+extern uint32_t verbose;
+
+static void hid_dump_descriptor	(report_desc_t r);
+static void hid_dump_item	(char const *label, struct hid_item *h);
+
+static int
+hid_dump(bdaddr_t *bdaddr, int argc, char **argv)
+{
+	struct hid_device	*hd = NULL;
+	int			 e = FAILED;
+
+	if (read_config_file() == 0) {
+		if ((hd = get_hid_device(bdaddr)) != NULL) {
+			hid_dump_descriptor(hd->desc);
+			e = OK;
+		} 
+
+		clean_config();
+	}
+
+	return (e);
+}
+
+static int
+hid_forget(bdaddr_t *bdaddr, int argc, char **argv)
+{
+	struct hid_device	*hd = NULL;
+	int			 e = FAILED;
+
+	if (read_config_file() == 0) {
+		if (read_hids_file() == 0) {
+			if ((hd = get_hid_device(bdaddr)) != NULL) {
+				hd->new_device = 1;
+				if (write_hids_file() == 0)
+					e = OK;
+			}
+		}
+
+		clean_config();
+	}
+
+	return (e);
+}
+
+static int
+hid_known(bdaddr_t *bdaddr, int argc, char **argv)
+{
+	struct hid_device	*hd = NULL;
+	struct hostent		*he = NULL;
+	int			 e = FAILED;
+
+	if (read_config_file() == 0) {
+		if (read_hids_file() == 0) {
+			e = OK;
+
+			for (hd = get_next_hid_device(hd);
+			     hd != NULL;
+			     hd = get_next_hid_device(hd)) {
+				if (hd->new_device)
+					continue;
+
+				he = bt_gethostbyaddr((char *) &hd->bdaddr,
+						sizeof(hd->bdaddr),
+						AF_BLUETOOTH);
+
+				fprintf(stdout,
+"%s %s\n",				bt_ntoa(&hd->bdaddr, NULL),
+					(he != NULL && he->h_name != NULL)?
+						he->h_name : "");
+			}
+		}
+
+		clean_config();
+	}
+
+	return (e);
+}
+
+static void
+hid_dump_descriptor(report_desc_t r)
+{
+	struct hid_data	*d = NULL;
+	struct hid_item	 h;
+
+	for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) {
+		switch (h.kind) {
+		case hid_collection:
+			fprintf(stdout,
+"Collection page=%s usage=%s\n", hid_usage_page(HID_PAGE(h.usage)),
+				 hid_usage_in_page(h.usage));
+			break;
+
+		case hid_endcollection:
+			fprintf(stdout, "End collection\n");
+			break;
+
+		case hid_input:
+			hid_dump_item("Input  ", &h);
+			break;
+
+		case hid_output:
+			hid_dump_item("Output ", &h);
+			break;
+
+		case hid_feature:
+			hid_dump_item("Feature", &h);
+			break;
+		}
+	}
+
+	hid_end_parse(d);
+}
+
+static void
+hid_dump_item(char const *label, struct hid_item *h)
+{
+	if ((h->flags & HIO_CONST) && !verbose)
+		return;
+
+	fprintf(stdout,
+"%s id=%u size=%u count=%u page=%s usage=%s%s%s%s%s%s%s%s%s%s",
+		label, (uint8_t) h->report_ID, h->report_size, h->report_count,
+		hid_usage_page(HID_PAGE(h->usage)),
+		hid_usage_in_page(h->usage),
+		h->flags & HIO_CONST ? " Const" : "",
+		h->flags & HIO_VARIABLE ? " Variable" : "",
+		h->flags & HIO_RELATIVE ? " Relative" : "",
+		h->flags & HIO_WRAP ? " Wrap" : "",
+		h->flags & HIO_NONLINEAR ? " NonLinear" : "",
+		h->flags & HIO_NOPREF ? " NoPref" : "",
+		h->flags & HIO_NULLSTATE ? " NullState" : "",
+		h->flags & HIO_VOLATILE ? " Volatile" : "",
+		h->flags & HIO_BUFBYTES ? " BufBytes" : "");
+
+	fprintf(stdout,
+", logical range %d..%d",
+		h->logical_minimum, h->logical_maximum);
+
+	if (h->physical_minimum != h->physical_maximum)
+		fprintf(stdout,
+", physical range %d..%d",
+			h->physical_minimum, h->physical_maximum);
+
+	if (h->unit)
+		fprintf(stdout,
+", unit=0x%02x exp=%d", h->unit, h->unit_exponent);
+
+	fprintf(stdout, "\n");
+}
+
+struct bthid_command	hid_commands[] = {
+{
+"Dump",
+"Dump HID descriptor for the specified device in human readable form. The\n" \
+"device must have an entry in the Bluetooth HID daemon configuration file.\n",
+hid_dump
+},
+{
+"Known",
+"List all known to the Bluetooth HID daemon devices.\n",
+hid_known
+},
+{
+"Forget",
+"Forget (mark as new) specified HID device. This command is useful when it\n" \
+"is required to remove device from the known HIDs file. This should be done\n" \
+"when reset button was pressed on the device or the battery was changed. The\n"\
+"Bluetooth HID daemon should be restarted.\n",
+hid_forget
+},
+{ NULL, NULL, NULL }
+};
+
diff --git a/usr.sbin/bthidcontrol/sdp.c b/usr.sbin/bthidcontrol/sdp.c
new file mode 100644
index 0000000000..de4ef42bd7
--- /dev/null
+++ b/usr.sbin/bthidcontrol/sdp.c
@@ -0,0 +1,434 @@
+/*
+ * sdp.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: sdp.c,v 1.3 2004/02/17 22:14:57 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidcontrol/sdp.c 212296 2010-09-07 16:36:03Z emax $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usbhid.h>
+#include <errno.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <string.h>
+#include <usbhid.h>
+#include "bthid_config.h"
+#include "bthidcontrol.h"
+
+static int32_t hid_sdp_query				(bdaddr_t const *local, struct hid_device *hd, int32_t *error);
+static int32_t hid_sdp_parse_protocol_descriptor_list	(sdp_attr_p a);
+static int32_t hid_sdp_parse_hid_descriptor		(sdp_attr_p a);
+static int32_t hid_sdp_parse_boolean			(sdp_attr_p a);
+
+static uint16_t		service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
+
+static uint32_t		attrs[] = {
+SDP_ATTR_RANGE(	SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+		SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
+SDP_ATTR_RANGE	(SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS,
+		SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS),
+SDP_ATTR_RANGE(	0x0205,		/* HIDReconnectInitiate */
+		0x0205),
+SDP_ATTR_RANGE(	0x0206,		/* HIDDescriptorList */
+		0x0206),
+SDP_ATTR_RANGE(	0x0209,		/* HIDBatteryPower */
+		0x0209),
+SDP_ATTR_RANGE(	0x020d,		/* HIDNormallyConnectable */
+		0x020d)
+	};
+#define	nattrs	(sizeof(attrs)/sizeof(attrs[0]))
+
+static sdp_attr_t	values[8];
+#define	nvalues	(sizeof(values)/sizeof(values[0]))
+
+static uint8_t		buffer[nvalues][512];
+
+/*
+ * Query remote device
+ */
+
+#undef	hid_sdp_query_exit
+#define	hid_sdp_query_exit(e) {		\
+	if (error != NULL)		\
+		*error = (e);		\
+	if (ss != NULL) {		\
+		sdp_close(ss);		\
+		ss = NULL;		\
+	}				\
+	return (((e) == 0)? 0 : -1);	\
+}
+
+static int32_t
+hid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error)
+{
+	void	*ss = NULL;
+	uint8_t	*hid_descriptor = NULL;
+	int32_t	 i, control_psm = -1, interrupt_psm = -1,
+		 reconnect_initiate = -1,
+		 normally_connectable = 0, battery_power = 0,
+		 hid_descriptor_length = -1;
+
+	if (local == NULL)
+		local = NG_HCI_BDADDR_ANY;
+	if (hd == NULL)
+		hid_sdp_query_exit(EINVAL);
+
+	for (i = 0; i < nvalues; i ++) {
+		values[i].flags = SDP_ATTR_INVALID;
+		values[i].attr = 0;
+		values[i].vlen = sizeof(buffer[i]);
+		values[i].value = buffer[i];
+	}
+
+	if ((ss = sdp_open(local, &hd->bdaddr)) == NULL)
+		hid_sdp_query_exit(ENOMEM);
+	if (sdp_error(ss) != 0)
+		hid_sdp_query_exit(sdp_error(ss));
+	if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0)
+                hid_sdp_query_exit(sdp_error(ss));
+
+        sdp_close(ss);
+        ss = NULL;
+
+	for (i = 0; i < nvalues; i ++) {
+		if (values[i].flags != SDP_ATTR_OK)
+			continue;
+
+		switch (values[i].attr) {
+		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
+			control_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]);
+			break;
+
+		case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS:
+			interrupt_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]);
+			break;
+
+		case 0x0205: /* HIDReconnectInitiate */
+			reconnect_initiate = hid_sdp_parse_boolean(&values[i]);
+			break;
+
+		case 0x0206: /* HIDDescriptorList */
+			if (hid_sdp_parse_hid_descriptor(&values[i]) == 0) {
+				hid_descriptor = values[i].value;
+				hid_descriptor_length = values[i].vlen;
+			}
+			break;
+
+		case 0x0209: /* HIDBatteryPower */
+			battery_power = hid_sdp_parse_boolean(&values[i]);
+			break;
+
+		case 0x020d: /* HIDNormallyConnectable */
+			normally_connectable = hid_sdp_parse_boolean(&values[i]);
+			break;
+		}
+	}
+
+	if (control_psm == -1 || interrupt_psm == -1 ||
+	    reconnect_initiate == -1 ||
+	    hid_descriptor == NULL || hid_descriptor_length == -1)
+		hid_sdp_query_exit(ENOATTR);
+
+	hd->control_psm = control_psm;
+	hd->interrupt_psm = interrupt_psm;
+	hd->reconnect_initiate = reconnect_initiate? 1 : 0;
+	hd->battery_power = battery_power? 1 : 0;
+	hd->normally_connectable = normally_connectable? 1 : 0;
+	hd->desc = hid_use_report_desc(hid_descriptor, hid_descriptor_length);
+	if (hd->desc == NULL)
+		hid_sdp_query_exit(ENOMEM);
+
+	return (0);
+}
+
+/*
+ * seq len				2
+ *	seq len				2
+ *		uuid value		3
+ *		uint16 value		3
+ *		seq len			2
+ *			uuid value	3
+ */
+
+static int32_t
+hid_sdp_parse_protocol_descriptor_list(sdp_attr_p a)
+{
+	uint8_t	*ptr = a->value;
+	uint8_t	*end = a->value + a->vlen;
+	int32_t	 type, len, uuid, psm;
+
+	if (end - ptr < 15)
+		return (-1);
+
+	if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) {
+		SDP_GET8(type, ptr);
+		switch (type) {
+		case SDP_DATA_SEQ8:
+			SDP_GET8(len, ptr);
+			break;
+
+		case SDP_DATA_SEQ16:
+			SDP_GET16(len, ptr);
+			break;
+
+		case SDP_DATA_SEQ32:
+			SDP_GET32(len, ptr);
+			break;
+
+		default:
+			return (-1);
+		}
+		if (ptr + len > end)
+			return (-1);
+	}
+
+	SDP_GET8(type, ptr);
+	switch (type) {
+	case SDP_DATA_SEQ8:
+		SDP_GET8(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ16:
+		SDP_GET16(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ32:
+		SDP_GET32(len, ptr);
+		break;
+
+	default:
+		return (-1);
+	}
+	if (ptr + len > end)
+		return (-1);
+
+	/* Protocol */
+	SDP_GET8(type, ptr);
+	switch (type) {
+	case SDP_DATA_SEQ8:
+		SDP_GET8(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ16:
+		SDP_GET16(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ32:
+		SDP_GET32(len, ptr);
+		break;
+
+	default:
+		return (-1);
+	}
+	if (ptr + len > end)
+		return (-1);
+
+	/* UUID */
+	if (ptr + 3 > end)
+		return (-1);
+	SDP_GET8(type, ptr);
+	switch (type) {
+	case SDP_DATA_UUID16:
+		SDP_GET16(uuid, ptr);
+		if (uuid != SDP_UUID_PROTOCOL_L2CAP)
+			return (-1);
+		break;
+
+	case SDP_DATA_UUID32:  /* XXX FIXME can we have 32-bit UUID */
+	case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
+	default:
+		return (-1);
+	}
+
+	/* PSM */
+	if (ptr + 3 > end)
+		return (-1);
+	SDP_GET8(type, ptr);
+	if (type != SDP_DATA_UINT16)
+		return (-1);
+	SDP_GET16(psm, ptr);
+
+	return (psm);
+}
+
+/*
+ * seq len			2
+ *	seq len			2
+ *		uint8 value8	2
+ * 		str value	3
+ */
+
+static int32_t
+hid_sdp_parse_hid_descriptor(sdp_attr_p a)
+{
+	uint8_t	*ptr = a->value;
+	uint8_t	*end = a->value + a->vlen;
+	int32_t	 type, len, descriptor_type;
+
+	if (end - ptr < 9)
+		return (-1);
+
+	SDP_GET8(type, ptr);
+	switch (type) {
+	case SDP_DATA_SEQ8:
+		SDP_GET8(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ16:
+		SDP_GET16(len, ptr);
+		break;
+
+	case SDP_DATA_SEQ32:
+		SDP_GET32(len, ptr);
+		break;
+
+	default:
+		return (-1);
+	}
+	if (ptr + len > end)
+		return (-1);
+
+	while (ptr < end) {
+		/* Descriptor */
+		SDP_GET8(type, ptr);
+		switch (type) {
+		case SDP_DATA_SEQ8:
+			if (ptr + 1 > end)
+				return (-1);
+			SDP_GET8(len, ptr);
+			break;
+
+		case SDP_DATA_SEQ16:
+			if (ptr + 2 > end)
+				return (-1);
+			SDP_GET16(len, ptr);
+			break;
+
+		case SDP_DATA_SEQ32:
+			if (ptr + 4 > end)
+				return (-1);
+			SDP_GET32(len, ptr);
+			break;
+
+		default:
+			return (-1);
+		}
+
+		/* Descripor type */
+		if (ptr + 1 > end)
+			return (-1);
+		SDP_GET8(type, ptr);
+		if (type != SDP_DATA_UINT8 || ptr + 1 > end)
+			return (-1);
+		SDP_GET8(descriptor_type, ptr);
+
+		/* Descriptor value */
+		if (ptr + 1 > end)
+			return (-1);
+		SDP_GET8(type, ptr);
+		switch (type) {
+		case SDP_DATA_STR8:
+			if (ptr + 1 > end)
+				return (-1);
+			SDP_GET8(len, ptr);
+			break;
+
+		case SDP_DATA_STR16:
+			if (ptr + 2 > end)
+				return (-1);
+			SDP_GET16(len, ptr);
+			break;
+
+		case SDP_DATA_STR32:
+			if (ptr + 4 > end)
+				return (-1);
+			SDP_GET32(len, ptr);
+			break;
+
+		default:
+			return (-1);
+		}
+		if (ptr + len > end)
+			return (-1);
+
+		if (descriptor_type == UDESC_REPORT && len > 0) {
+			a->value = ptr;
+			a->vlen = len;
+
+			return (0);
+		}
+
+		ptr += len;
+	}
+
+	return (-1);
+}
+
+/* bool8 int8 */
+static int32_t
+hid_sdp_parse_boolean(sdp_attr_p a)
+{
+	if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL)
+		return (-1);
+
+	return (a->value[1]);
+}
+
+/* Perform SDP query */
+static int32_t
+hid_query(bdaddr_t *bdaddr, int argc, char **argv)
+{
+	struct hid_device	hd;
+	int			e;
+
+	memcpy(&hd.bdaddr, bdaddr, sizeof(hd.bdaddr));
+	if (hid_sdp_query(NULL, &hd, &e) < 0) {
+		fprintf(stderr, "Could not perform SDP query on the " \
+			"device %s. %s (%d)\n", bt_ntoa(bdaddr, NULL),
+			strerror(e), e);
+		return (FAILED);
+	}
+
+	print_hid_device(&hd, stdout);
+
+	return (OK);
+}
+
+struct bthid_command	sdp_commands[] =
+{
+{
+"Query",
+"Perform SDP query to the specified device and print HID configuration entry\n"\
+"for the device. The configuration entry should be appended to the Bluetooth\n"\
+"HID daemon configuration file and the daemon should be restarted.\n",
+hid_query
+},
+{ NULL, NULL, NULL }
+};
+
diff --git a/usr.sbin/bthidd/Makefile b/usr.sbin/bthidd/Makefile
new file mode 100644
index 0000000000..5794985fb4
--- /dev/null
+++ b/usr.sbin/bthidd/Makefile
@@ -0,0 +1,18 @@
+# $Id: Makefile,v 1.6 2006/09/07 21:36:55 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/bthidd/Makefile 249657 2013-04-19 19:45:00Z ed $
+
+PROG=		bthidd
+MAN=		bthidd.8
+#		bthidd.conf.5
+SRCS=		bthidd.c client.c hid.c kbd.c lexer.l parser.y server.c \
+		session.c
+
+CFLAGS+=	-I${.CURDIR}
+DEBUG_FLAGS=	-g
+
+DPADD=          ${LIBBLUETOOTH} ${LIBUSBHID}
+LDADD=		-lbluetooth -lusbhid
+
+NO_WMISSING_VARIABLE_DECLARATIONS=
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bthidd/bthid_config.h b/usr.sbin/bthidd/bthid_config.h
new file mode 100644
index 0000000000..81481b29b3
--- /dev/null
+++ b/usr.sbin/bthidd/bthid_config.h
@@ -0,0 +1,70 @@
+/*
+ * bthid_config.h
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: bthid_config.h,v 1.4 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/bthid_config.h 162128 2006-09-07 21:47:49Z emax $
+ */
+
+#ifndef _BTHID_CONFIG_H_
+#define _BTHID_CONFIG_H_ 1
+
+#define BTHIDD_CONFFILE		"/etc/bluetooth/bthidd.conf"
+#define BTHIDD_HIDSFILE		"/var/db/bthidd.hids"
+
+struct hid_device
+{
+	bdaddr_t		bdaddr;		/* HID device BDADDR */
+	uint16_t		control_psm;	/* control PSM */
+	uint16_t		interrupt_psm;	/* interrupt PSM */
+	unsigned		new_device           : 1;
+	unsigned		reconnect_initiate   : 1;
+	unsigned		battery_power        : 1;
+	unsigned		normally_connectable : 1;
+	unsigned		keyboard             : 1;
+	unsigned		reserved             : 11;
+	report_desc_t		desc;		/* HID report descriptor */
+	LIST_ENTRY(hid_device)	next;		/* link to the next */
+};
+typedef struct hid_device	hid_device_t;
+typedef struct hid_device *	hid_device_p;
+
+extern char const	*config_file;
+extern char const	*hids_file;
+
+int32_t		read_config_file	(void);
+void		clean_config		(void);
+hid_device_p	get_hid_device		(bdaddr_p bdaddr);
+hid_device_p	get_next_hid_device	(hid_device_p d);
+void		print_hid_device	(hid_device_p hid_device, FILE *f);
+
+int32_t		read_hids_file		(void);
+int32_t		write_hids_file		(void);
+
+#endif /* ndef _BTHID_CONFIG_H_ */
+
diff --git a/usr.sbin/bthidd/bthidd.8 b/usr.sbin/bthidd/bthidd.8
new file mode 100644
index 0000000000..6aeb16bcb0
--- /dev/null
+++ b/usr.sbin/bthidd/bthidd.8
@@ -0,0 +1,127 @@
+.\" Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: bthidd.8,v 1.1 2006/09/07 21:36:55 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/bthidd/bthidd.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd September 7, 2006
+.Dt BTHIDD 8
+.Os
+.Sh NAME
+.Nm bthidd
+.Nd Bluetooth HID daemon
+.Sh SYNOPSIS
+.Nm
+.Fl h
+.Nm
+.Op Fl a Ar BD_ADDR
+.Op Fl c Ar file
+.Op Fl H Ar file
+.Op Fl p Ar file
+.Op Fl t Ar val
+.Sh DESCRIPTION
+The
+.Nm
+daemon handles remote Bluetooth HID devices.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar BD_ADDR
+Specify the local address to listen on.
+By default, the server will listen on
+.Dv ANY
+address.
+The address can be specified as BD_ADDR or name.
+If a name was specified, the
+.Nm
+daemon will attempt to resolve the name via
+.Xr bt_gethostbyname 3 .
+.It Fl c Ar file
+Specify path to the configuration file.
+The default path is
+.Pa /etc/bluetooth/bthidd.conf .
+.It Fl d
+Do not detach from the controlling terminal, i.e., run in foreground.
+.It Fl H Ar file
+Specify path to the known HIDs file.
+The default path is
+.Pa /var/db/bthidd.hids .
+.It Fl h
+Display usage message and exit.
+.It Fl p Ar file
+Specify path to the PID file.
+The default path is
+.Pa /var/run/bthidd.pid .
+.It Fl t Ar val
+Specify client rescan interval in seconds.
+The
+.Nm
+daemon will periodically scan for newly configured Bluetooth HID devices or
+disconnected
+.Dq passive
+Bluetooth HID devices and will attempt to establish an outgoing connection.
+The default rescan interval is 10 seconds.
+.El
+.Sh KNOWN LIMITATIONS
+The
+.Nm
+daemon currently does not handle key auto repeat and double click mouse events.
+Those events work under
+.Xr X 7
+just fine,
+but not in text console.
+.Pp
+This manual page needs more work.
+A manual page documenting the format of the
+.Pa /etc/bluetooth/bthidd.conf
+configuration file is needed as well.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/bluetooth/bthidd.conf" -compact
+.It Pa /etc/bluetooth/bthidd.conf
+.It Pa /var/db/bthidd.hids
+.It Pa /var/run/bthidd.pid
+.El
+.Sh SEE ALSO
+.Xr kbdmux 4 ,
+.Xr vkbd 4 ,
+.Xr bthidcontrol 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh CAVEATS
+Any Bluetooth HID device that has
+.Dv HUP_KEYBOARD
+or
+.Dv HUP_CONSUMER
+entries in its descriptor is considered as
+.Dq keyboard .
+For each
+.Dq keyboard
+Bluetooth HID device,
+the
+.Nm
+daemon will use a separate instance of the virtual keyboard interface
+.Xr vkbd 4 .
+Therefore the
+.Xr kbdmux 4
+driver must be used to properly multiplex input from multiple keyboards.
diff --git a/usr.sbin/bthidd/bthidd.c b/usr.sbin/bthidd/bthidd.c
new file mode 100644
index 0000000000..245bd7da65
--- /dev/null
+++ b/usr.sbin/bthidd/bthidd.c
@@ -0,0 +1,266 @@
+/*
+ * bthidd.c
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: bthidd.c,v 1.8 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/bthidd.c 162128 2006-09-07 21:47:49Z emax $
+ */
+
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <usbhid.h>
+#include "bthid_config.h"
+#include "bthidd.h"
+
+static int32_t	write_pid_file	(char const *file);
+static int32_t	remove_pid_file	(char const *file);
+static int32_t	elapsed		(int32_t tval);
+static void	sighandler	(int32_t s);
+static void	usage		(void);
+
+/*
+ * bthidd
+ */
+
+static int32_t	done = 0; /* are we done? */
+
+int32_t
+main(int32_t argc, char *argv[])
+{
+	struct bthid_server	 srv;
+	struct sigaction	 sa;
+	char const		*pid_file = BTHIDD_PIDFILE;
+	char			*ep;
+	int32_t			 opt, detach, tval;
+
+	memset(&srv, 0, sizeof(srv));
+	memset(&srv.bdaddr, 0, sizeof(srv.bdaddr));
+	detach = 1;
+	tval = 10; /* sec */
+
+	while ((opt = getopt(argc, argv, "a:c:dH:hp:t:")) != -1) {
+		switch (opt) {
+		case 'a': /* BDADDR */
+			if (!bt_aton(optarg, &srv.bdaddr)) {
+				struct hostent  *he;
+
+				if ((he = bt_gethostbyname(optarg)) == NULL)
+					errx(1, "%s: %s", optarg, hstrerror(h_errno));
+
+				memcpy(&srv.bdaddr, he->h_addr, sizeof(srv.bdaddr));
+			}
+			break;
+			
+		case 'c': /* config file */
+			config_file = optarg;
+			break;
+
+		case 'd': /* do not detach */
+			detach = 0;
+			break;
+
+		case 'H': /* hids file */
+			hids_file = optarg;
+			break;
+
+		case 'p': /* pid file */
+			pid_file = optarg;
+			break;
+
+		case 't': /* rescan interval */
+			tval = strtol(optarg, (char **) &ep, 10);
+			if (*ep != '\0' || tval <= 0)
+				usage();
+			break;
+
+		case 'h':
+		default:
+			usage();
+			/* NOT REACHED */
+		}
+	}
+
+	openlog(BTHIDD_IDENT, LOG_PID|LOG_PERROR|LOG_NDELAY, LOG_USER);
+
+	/* Become daemon if required */
+	if (detach && daemon(0, 0) < 0) {
+		syslog(LOG_CRIT, "Could not become daemon. %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	/* Install signal handler */
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = sighandler;
+
+	if (sigaction(SIGTERM, &sa, NULL) < 0 ||
+	    sigaction(SIGHUP, &sa, NULL) < 0 ||
+	    sigaction(SIGINT, &sa, NULL) < 0) {
+		syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	sa.sa_handler = SIG_IGN;
+	if (sigaction(SIGPIPE, &sa, NULL) < 0) {
+		syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	sa.sa_handler = SIG_IGN;
+	sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT;
+	if (sigaction(SIGCHLD, &sa, NULL) < 0) {
+		syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	if (read_config_file() < 0 || read_hids_file() < 0 ||
+	    server_init(&srv) < 0 || write_pid_file(pid_file) < 0)
+		exit(1);
+
+	for (done = 0; !done; ) {
+		if (elapsed(tval))
+			client_rescan(&srv);
+
+		if (server_do(&srv) < 0)
+			break;
+	}
+
+	server_shutdown(&srv);
+	remove_pid_file(pid_file);
+	clean_config();
+	closelog();
+
+	return (0);
+}
+
+/*
+ * Write pid file
+ */
+
+static int32_t
+write_pid_file(char const *file)
+{
+	FILE	*pid;
+
+	assert(file != NULL);
+
+	if ((pid = fopen(file, "w")) == NULL) {
+		syslog(LOG_ERR, "Could not open file %s. %s (%d)",
+			file, strerror(errno), errno);
+		return (-1);
+	}
+
+	fprintf(pid, "%d", getpid());
+	fclose(pid);
+
+	return (0);
+}
+
+/*
+ * Remote pid file
+ */
+
+static int32_t
+remove_pid_file(char const *file)
+{
+	assert(file != NULL);
+
+	if (unlink(file) < 0) {
+		syslog(LOG_ERR, "Could not unlink file %s. %s (%d)",
+			file, strerror(errno), errno);
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * Returns true if desired time interval has elapsed
+ */
+
+static int32_t
+elapsed(int32_t tval)
+{
+	static struct timeval	last = { 0, 0 };
+	struct timeval		now;
+
+	gettimeofday(&now, NULL);
+
+	if (now.tv_sec - last.tv_sec >= tval) {
+		last = now;
+		return (1);
+	}
+
+	return (0);
+}
+
+/*
+ * Signal handler
+ */
+
+static void
+sighandler(int32_t s)
+{
+	syslog(LOG_NOTICE, "Got signal %d, total number of signals %d",
+		s, ++ done);
+}
+
+/*
+ * Display usage and exit
+ */
+
+static void
+usage(void)
+{
+	fprintf(stderr,
+"Usage: %s [options]\n" \
+"Where options are:\n" \
+"	-a address	specify address to listen on (default ANY)\n" \
+"	-c file		specify config file name\n" \
+"	-d		run in foreground\n" \
+"	-H file		specify known HIDs file name\n" \
+"	-h		display this message\n" \
+"	-p file		specify PID file name\n" \
+"	-t tval		specify client rescan interval (sec)\n" \
+"", BTHIDD_IDENT);
+	exit(255);
+}
+
diff --git a/usr.sbin/bthidd/bthidd.conf.sample b/usr.sbin/bthidd/bthidd.conf.sample
new file mode 100644
index 0000000000..a1afed2ce5
--- /dev/null
+++ b/usr.sbin/bthidd/bthidd.conf.sample
@@ -0,0 +1,72 @@
+# $FreeBSD: head/usr.sbin/bluetooth/bthidd/bthidd.conf.sample 162128 2006-09-07 21:47:49Z emax $
+
+device {
+	bdaddr			00:50:f2:e5:68:84;
+	control_psm		0x11;
+	interrupt_psm		0x13;
+	reconnect_initiate	true;
+	normally_connectable	false;
+	hid_descriptor		{
+		0x05 0x01 0x09 0x02 0xa1 0x01 0x85 0x02 
+		0x09 0x01 0xa1 0x00 0x05 0x09 0x19 0x01 
+		0x29 0x05 0x15 0x00 0x25 0x01 0x75 0x01 
+		0x95 0x05 0x81 0x02 0x75 0x03 0x95 0x01 
+		0x81 0x01 0x05 0x01 0x09 0x30 0x09 0x31 
+		0x09 0x38 0x15 0x81 0x25 0x7f 0x75 0x08 
+		0x95 0x03 0x81 0x06 0xc0 0xc0 0x05 0x0c 
+		0x09 0x01 0xa1 0x01 0x85 0x03 0x05 0x01 
+		0x09 0x02 0xa1 0x02 0x06 0x00 0xff 0x15 
+		0x00 0x25 0x03 0x95 0x01 0x75 0x02 0x0a 
+		0x01 0xfe 0x81 0x02 0x75 0x06 0x81 0x01 
+		0xc0 0xc0 
+	};
+}
+
+device {
+	bdaddr			00:50:f2:e3:fb:e1;
+	control_psm		0x11;
+	interrupt_psm		0x13;
+	reconnect_initiate	true;
+	normally_connectable	false;
+	hid_descriptor		{
+		0x05 0x01 0x09 0x06 0xa1 0x01 0x85 0x01 
+		0x05 0x08 0x19 0x01 0x29 0x03 0x15 0x00 
+		0x25 0x01 0x75 0x01 0x95 0x03 0x91 0x02 
+		0x09 0x4b 0x95 0x01 0x91 0x02 0x95 0x04 
+		0x91 0x01 0x05 0x07 0x19 0xe0 0x29 0xe7 
+		0x95 0x08 0x81 0x02 0x75 0x08 0x95 0x01 
+		0x81 0x01 0x19 0x00 0x29 0x91 0x26 0xff 
+		0x00 0x95 0x06 0x81 0x00 0xc0 0x05 0x0c 
+		0x09 0x01 0xa1 0x01 0x85 0x02 0x05 0x0c 
+		0x15 0x00 0x25 0x01 0x75 0x01 0x95 0x1c 
+		0x09 0xe2 0x09 0xb7 0x09 0xcd 0x09 0xea 
+		0x09 0xe9 0x09 0xb6 0x09 0xb5 0x0a 0x83 
+		0x01 0x0a 0x1a 0x02 0x0a 0x79 0x02 0x0a 
+		0xab 0x01 0x0a 0x08 0x02 0x0a 0x02 0x02 
+		0x0a 0x03 0x02 0x0a 0x07 0x02 0x0a 0x01 
+		0x02 0x0a 0x92 0x01 0x0a 0x9c 0x01 0x09 
+		0x95 0x0a 0x23 0x02 0x0a 0x89 0x02 0x0a 
+		0x8b 0x02 0x0a 0x8c 0x02 0x0a 0x8a 0x01 
+		0x0a 0x99 0x01 0x0a 0xa7 0x01 0x0a 0xb6 
+		0x01 0x0a 0xb7 0x01 0x81 0x02 0x75 0x01 
+		0x95 0x04 0x81 0x01 0x06 0x00 0xff 0x0a 
+		0x02 0xff 0x26 0xff 0x00 0x95 0x01 0x75 
+		0x08 0x81 0x02 0xc0 0x05 0x01 0x09 0x80 
+		0xa1 0x01 0x85 0x03 0x19 0x81 0x29 0x83 
+		0x25 0x01 0x95 0x03 0x75 0x01 0x81 0x02 
+		0x95 0x05 0x81 0x01 0xc0 0x05 0x0c 0x09 
+		0x01 0xa1 0x01 0x85 0x04 0x05 0x01 0x09 
+		0x06 0xa1 0x02 0x06 0x00 0xff 0x15 0x00 
+		0x25 0x03 0x95 0x01 0x75 0x02 0x0a 0x01 
+		0xfe 0x81 0x02 0x75 0x06 0x81 0x01 0xc0 
+		0xc0 0x05 0x0c 0x09 0x01 0xa1 0x01 0x85 
+		0x05 0x05 0x01 0x09 0x06 0xa1 0x02 0x06 
+		0x00 0xff 0x25 0x01 0x75 0x01 0x95 0x02 
+		0x0a 0x03 0xfe 0x0a 0x04 0xfe 0x81 0x02 
+		0x95 0x06 0x81 0x01 0xc0 0xc0 0x05 0x0c 
+		0x09 0x01 0xa1 0x01 0x85 0xff 0x05 0x06 
+		0x95 0x01 0x75 0x02 0x19 0x24 0x29 0x26 
+		0x81 0x02 0x75 0x06 0x81 0x01 0xc0 
+	};
+}
+
diff --git a/usr.sbin/bthidd/bthidd.h b/usr.sbin/bthidd/bthidd.h
new file mode 100644
index 0000000000..d6e412358a
--- /dev/null
+++ b/usr.sbin/bthidd/bthidd.h
@@ -0,0 +1,93 @@
+/*
+ * bthidd.h
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: bthidd.h,v 1.7 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/bthidd.h 162128 2006-09-07 21:47:49Z emax $
+ */
+
+#ifndef _BTHIDD_H_
+#define _BTHIDD_H_ 1
+
+#define BTHIDD_IDENT	"bthidd"
+#define BTHIDD_PIDFILE	"/var/run/" BTHIDD_IDENT ".pid"
+
+struct bthid_session;
+
+struct bthid_server
+{
+	bdaddr_t			 bdaddr; /* local bdaddr */
+	int32_t				 cons;	 /* /dev/consolectl */
+	int32_t				 ctrl;   /* control channel (listen) */
+	int32_t				 intr;   /* intr. channel (listen) */
+	int32_t				 maxfd;	 /* max fd in sets */
+	fd_set				 rfdset; /* read descriptor set */
+	fd_set				 wfdset; /* write descriptor set */
+	LIST_HEAD(, bthid_session)	 sessions;
+};
+
+typedef struct bthid_server	bthid_server_t;
+typedef struct bthid_server *	bthid_server_p;
+
+struct bthid_session
+{
+	bthid_server_p			 srv;	/* pointer back to server */
+	int32_t				 ctrl;	/* control channel */
+	int32_t				 intr;	/* interrupt channel */
+	int32_t				 vkbd;	/* virual keyboard */
+	bdaddr_t			 bdaddr;/* remote bdaddr */
+	uint16_t			 state;	/* session state */
+#define CLOSED	0
+#define	W4CTRL	1
+#define	W4INTR	2
+#define	OPEN	3
+	bitstr_t			*keys1;	/* keys map (new) */
+	bitstr_t			*keys2;	/* keys map (old) */
+	LIST_ENTRY(bthid_session)	 next;	/* link to next */
+};
+
+typedef struct bthid_session	bthid_session_t;
+typedef struct bthid_session *	bthid_session_p;
+
+int32_t		server_init      (bthid_server_p srv);
+void		server_shutdown  (bthid_server_p srv);
+int32_t		server_do        (bthid_server_p srv);
+
+int32_t		client_rescan    (bthid_server_p srv);
+int32_t		client_connect   (bthid_server_p srv, int fd);
+
+bthid_session_p	session_open     (bthid_server_p srv, hid_device_p const d);
+bthid_session_p	session_by_bdaddr(bthid_server_p srv, bdaddr_p bdaddr);
+bthid_session_p	session_by_fd    (bthid_server_p srv, int32_t fd);
+void		session_close    (bthid_session_p s);
+
+int32_t		hid_control      (bthid_session_p s, uint8_t *data, int32_t len);
+int32_t		hid_interrupt    (bthid_session_p s, uint8_t *data, int32_t len);
+
+#endif /* ndef _BTHIDD_H_ */
+
diff --git a/usr.sbin/bthidd/client.c b/usr.sbin/bthidd/client.c
new file mode 100644
index 0000000000..bd3c03f293
--- /dev/null
+++ b/usr.sbin/bthidd/client.c
@@ -0,0 +1,256 @@
+/*
+ * client.c
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: client.c,v 1.7 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/client.c 163918 2006-11-02 18:57:09Z emax $
+ */
+
+#include <sys/queue.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <usbhid.h>
+#include "bthid_config.h"
+#include "bthidd.h"
+
+static int32_t	client_socket(bdaddr_p bdaddr, uint16_t psm);
+
+/*
+ * Get next config entry and create outbound connection (if required)
+ *
+ * XXX	Do only one device at a time. At least one of my devices (3COM
+ *	Bluetooth PCCARD) rejects Create_Connection command if another
+ *	Create_Connection command is still pending. Weird...
+ */
+
+static int32_t	connect_in_progress = 0;
+
+int32_t
+client_rescan(bthid_server_p srv)
+{
+	static hid_device_p	d;
+	bthid_session_p		s;
+
+	assert(srv != NULL);
+
+	if (connect_in_progress)
+		return (0); /* another connect is still pending */ 
+
+	d = get_next_hid_device(d);
+	if (d == NULL)
+		return (0); /* XXX should not happen? empty config? */
+
+	if ((s = session_by_bdaddr(srv, &d->bdaddr)) != NULL)
+		return (0); /* session already active */
+
+	if (!d->new_device) {
+		if (d->reconnect_initiate)
+			return (0); /* device will initiate reconnect */
+	}
+
+	syslog(LOG_NOTICE, "Opening outbound session for %s " \
+		"(new_device=%d, reconnect_initiate=%d)",
+		bt_ntoa(&d->bdaddr, NULL), d->new_device, d->reconnect_initiate);
+
+	if ((s = session_open(srv, d)) == NULL) {
+		syslog(LOG_CRIT, "Could not create outbound session for %s",
+			bt_ntoa(&d->bdaddr, NULL));
+		return (-1);
+	}
+
+	/* Open control channel */
+	s->ctrl = client_socket(&s->bdaddr, d->control_psm);
+	if (s->ctrl < 0) {
+		syslog(LOG_ERR, "Could not open control channel to %s. %s (%d)",
+			bt_ntoa(&s->bdaddr, NULL), strerror(errno), errno);
+		session_close(s);
+		return (-1);
+	}
+
+	s->state = W4CTRL;
+
+	FD_SET(s->ctrl, &srv->wfdset);
+	if (s->ctrl > srv->maxfd)
+		srv->maxfd = s->ctrl;
+
+	connect_in_progress = 1;
+
+	return (0);
+}
+
+/*
+ * Process connect on the socket
+ */
+
+int32_t
+client_connect(bthid_server_p srv, int32_t fd)
+{
+	bthid_session_p	s;
+	hid_device_p	d;
+	int32_t		error;
+	socklen_t	len;
+
+	assert(srv != NULL);
+	assert(fd >= 0);
+
+	s = session_by_fd(srv, fd);
+	assert(s != NULL);
+
+	d = get_hid_device(&s->bdaddr);
+	assert(d != NULL);
+
+	error = 0;
+	len = sizeof(error);
+	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+		syslog(LOG_ERR, "Could not get socket error for %s. %s (%d)",
+			bt_ntoa(&s->bdaddr, NULL), strerror(errno), errno);
+		session_close(s);
+		connect_in_progress = 0;
+
+		return (-1);
+	}
+
+	if (error != 0) {
+		syslog(LOG_ERR, "Could not connect to %s. %s (%d)",
+			bt_ntoa(&s->bdaddr, NULL), strerror(error), error);
+		session_close(s);
+		connect_in_progress = 0;
+
+		return (0);
+	}
+
+	switch (s->state) {
+	case W4CTRL: /* Control channel is open */
+		assert(s->ctrl == fd);
+		assert(s->intr == -1);
+
+		/* Open interrupt channel */
+		s->intr = client_socket(&s->bdaddr, d->interrupt_psm);
+		if (s->intr < 0) { 
+			syslog(LOG_ERR, "Could not open interrupt channel " \
+				"to %s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
+				strerror(errno), errno);
+			session_close(s);
+			connect_in_progress = 0;
+
+			return (-1);
+		}
+
+		s->state = W4INTR;
+
+		FD_SET(s->intr, &srv->wfdset);
+		if (s->intr > srv->maxfd)
+			srv->maxfd = s->intr;
+
+		d->new_device = 0; /* reset new device flag */
+		write_hids_file();
+		break;
+
+	case W4INTR: /* Interrupt channel is open */
+		assert(s->ctrl != -1);
+		assert(s->intr == fd);
+
+		s->state = OPEN;
+		connect_in_progress = 0;
+
+		/* Register session's vkbd descriptor (if any) for read */
+		if (s->state == OPEN && d->keyboard) {
+			assert(s->vkbd != -1);
+
+			FD_SET(s->vkbd, &srv->rfdset);
+			if (s->vkbd > srv->maxfd)
+				srv->maxfd = s->vkbd;
+	        }
+		break;
+
+	default:
+		assert(0);
+		break;
+	}
+
+	/* Move fd to from the write fd set into read fd set */
+	FD_CLR(fd, &srv->wfdset);
+	FD_SET(fd, &srv->rfdset);
+
+	return (0);
+}
+
+/*
+ * Create bound non-blocking socket and initiate connect
+ */
+
+static int
+client_socket(bdaddr_p bdaddr, uint16_t psm)
+{
+	struct sockaddr_l2cap	l2addr;
+	int32_t			s, m;
+
+	s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
+	if (s < 0)
+		return (-1);
+
+	m = fcntl(s, F_GETFL);
+	if (m < 0) {
+		close(s);
+		return (-1);
+	}
+
+	if (fcntl(s, F_SETFL, (m|O_NONBLOCK)) < 0) {
+		close(s);
+		return (-1);
+	}
+
+	l2addr.l2cap_len = sizeof(l2addr);
+	l2addr.l2cap_family = AF_BLUETOOTH;
+	memset(&l2addr.l2cap_bdaddr, 0, sizeof(l2addr.l2cap_bdaddr));
+	l2addr.l2cap_psm = 0;
+
+	if (bind(s, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
+		close(s);
+		return (-1);
+	}
+
+	memcpy(&l2addr.l2cap_bdaddr, bdaddr, sizeof(l2addr.l2cap_bdaddr));
+	l2addr.l2cap_psm = htole16(psm);
+
+	if (connect(s, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0 &&
+	    errno != EINPROGRESS) {
+		close(s);
+		return (-1);
+	}
+
+	return (s);
+}
+
diff --git a/usr.sbin/bthidd/hid.c b/usr.sbin/bthidd/hid.c
new file mode 100644
index 0000000000..d73c475da8
--- /dev/null
+++ b/usr.sbin/bthidd/hid.c
@@ -0,0 +1,408 @@
+/*
+ * hid.c
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: hid.c,v 1.5 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/hid.c 221448 2011-05-04 17:58:15Z emax $
+ */
+
+#include <sys/consio.h>
+#include <sys/mouse.h>
+#include <sys/queue.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usbhid.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <usbhid.h>
+#include "bthid_config.h"
+#include "bthidd.h"
+#include "kbd.h"
+
+#undef	min
+#define	min(x, y)	(((x) < (y))? (x) : (y))
+
+#undef	ASIZE
+#define	ASIZE(a)	(sizeof(a)/sizeof(a[0]))
+
+/*
+ * Process data from control channel
+ */
+
+int32_t
+hid_control(bthid_session_p s, uint8_t *data, int32_t len)
+{
+	assert(s != NULL);
+	assert(data != NULL);
+	assert(len > 0);
+
+	switch (data[0] >> 4) {
+        case 0: /* Handshake (response to command) */
+		if (data[0] & 0xf)
+			syslog(LOG_ERR, "Got handshake message with error " \
+				"response 0x%x from %s",
+				data[0], bt_ntoa(&s->bdaddr, NULL));
+		break;
+
+	case 1: /* HID Control */
+		switch (data[0] & 0xf) {
+		case 0: /* NOP */
+			break;
+
+		case 1: /* Hard reset */
+		case 2: /* Soft reset */
+			syslog(LOG_WARNING, "Device %s requested %s reset",
+				bt_ntoa(&s->bdaddr, NULL),
+				((data[0] & 0xf) == 1)? "hard" : "soft");
+			break;
+
+		case 3: /* Suspend */
+			syslog(LOG_NOTICE, "Device %s requested Suspend",
+				bt_ntoa(&s->bdaddr, NULL));
+			break;
+
+		case 4: /* Exit suspend */
+			syslog(LOG_NOTICE, "Device %s requested Exit Suspend",
+				bt_ntoa(&s->bdaddr, NULL));
+			break;
+
+		case 5: /* Virtual cable unplug */
+			syslog(LOG_NOTICE, "Device %s unplugged virtual cable",
+				bt_ntoa(&s->bdaddr, NULL));
+			session_close(s);
+			break;
+
+		default:
+			syslog(LOG_WARNING, "Device %s sent unknown " \
+                                "HID_Control message 0x%x",
+				bt_ntoa(&s->bdaddr, NULL), data[0]);
+			break;
+		}
+		break;
+
+	default:
+		syslog(LOG_WARNING, "Got unexpected message 0x%x on Control " \
+			"channel from %s", data[0], bt_ntoa(&s->bdaddr, NULL));
+		break;
+	}
+
+	return (0);
+}
+
+/*
+ * Process data from the interrupt channel
+ */
+
+int32_t
+hid_interrupt(bthid_session_p s, uint8_t *data, int32_t len)
+{
+	hid_device_p	hid_device;
+	hid_data_t	d;
+	hid_item_t	h;
+	int32_t		report_id, usage, page, val,
+			mouse_x, mouse_y, mouse_z, mouse_butt,
+			mevents, kevents, i;
+
+	assert(s != NULL);
+	assert(s->srv != NULL);
+	assert(data != NULL);
+
+	if (len < 3) {
+		syslog(LOG_ERR, "Got short message (%d bytes) on Interrupt " \
+			"channel from %s", len, bt_ntoa(&s->bdaddr, NULL));
+		return (-1);
+	}
+
+	if (data[0] != 0xa1) {
+		syslog(LOG_ERR, "Got unexpected message 0x%x on " \
+			"Interrupt channel from %s",
+			data[0], bt_ntoa(&s->bdaddr, NULL));
+		return (-1);
+	}
+
+	report_id = data[1];
+	data ++;
+	len --;
+
+	hid_device = get_hid_device(&s->bdaddr);
+	assert(hid_device != NULL);
+
+	mouse_x = mouse_y = mouse_z = mouse_butt = mevents = kevents = 0;
+
+	for (d = hid_start_parse(hid_device->desc, 1 << hid_input, -1);
+	     hid_get_item(d, &h) > 0; ) {
+		if ((h.flags & HIO_CONST) || (h.report_ID != report_id) ||
+		    (h.kind != hid_input))
+			continue;
+
+		page = HID_PAGE(h.usage);
+		usage = HID_USAGE(h.usage);
+		val = hid_get_data(data, &h);
+
+		switch (page) {
+		case HUP_GENERIC_DESKTOP:
+			switch (usage) {
+			case HUG_X:
+				mouse_x = val;
+				mevents ++;
+				break;
+
+			case HUG_Y:
+				mouse_y = val;
+				mevents ++;
+				break;
+
+			case HUG_WHEEL:
+				mouse_z = -val;
+				mevents ++;
+				break;
+
+			case HUG_SYSTEM_SLEEP:
+				if (val)
+					syslog(LOG_NOTICE, "Sleep button pressed");
+				break;
+			}
+			break;
+
+		case HUP_KEYBOARD:
+			kevents ++;
+
+			if (h.flags & HIO_VARIABLE) {
+				if (val && usage < kbd_maxkey())
+					bit_set(s->keys1, usage);
+			} else {
+				if (val && val < kbd_maxkey())
+					bit_set(s->keys1, val);
+
+				for (i = 1; i < h.report_count; i++) {
+					h.pos += h.report_size;
+					val = hid_get_data(data, &h);
+					if (val && val < kbd_maxkey())
+						bit_set(s->keys1, val);
+				}
+			}
+			break;
+
+		case HUP_BUTTON:
+			if (usage != 0) {
+				if (usage == 2)
+					usage = 3;
+				else if (usage == 3)
+					usage = 2;
+				
+				mouse_butt |= (val << (usage - 1));
+				mevents ++;
+			}
+			break;
+
+		case HUP_CONSUMER:
+			if (!val)
+				break;
+
+			switch (usage) {
+			case HUC_AC_PAN:
+				/* Horizontal scroll */
+				if (val < 0)
+					mouse_butt |= (1 << 5);
+				else
+					mouse_butt |= (1 << 6);
+
+				mevents ++;
+				val = 0;
+				break;
+
+			case 0xb5: /* Scan Next Track */
+				val = 0x19;
+				break;
+
+			case 0xb6: /* Scan Previous Track */
+				val = 0x10;
+				break;
+
+			case 0xb7: /* Stop */
+				val = 0x24;
+				break;
+
+			case 0xcd: /* Play/Pause */
+				val = 0x22;
+				break;
+
+			case 0xe2: /* Mute */
+				val = 0x20;
+				break;
+
+			case 0xe9: /* Volume Up */
+				val = 0x30;
+				break;
+
+			case 0xea: /* Volume Down */
+				val = 0x2E;
+				break;
+
+			case 0x183: /* Media Select */
+				val = 0x6D;
+				break;
+
+			case 0x018a: /* Mail */
+				val = 0x6C;
+				break;
+
+			case 0x192: /* Calculator */
+				val = 0x21;
+				break;
+
+			case 0x194: /* My Computer */
+				val = 0x6B;
+				break;
+
+			case 0x221: /* WWW Search */
+				val = 0x65;
+				break;
+
+			case 0x223: /* WWW Home */
+				val = 0x32;
+				break;
+
+			case 0x224: /* WWW Back */
+				val = 0x6A;
+				break;
+
+			case 0x225: /* WWW Forward */
+				val = 0x69;
+				break;
+
+			case 0x226: /* WWW Stop */
+				val = 0x68;
+				break;
+
+			case 0x227: /* WWW Refresh */
+				val = 0x67;
+				break;
+
+			case 0x22a: /* WWW Favorites */
+				val = 0x66;
+				break;
+
+			default:
+				val = 0;
+				break;
+			}
+
+			/* XXX FIXME - UGLY HACK */
+			if (val != 0) {
+				if (hid_device->keyboard) {
+					int32_t	buf[4] = { 0xe0, val,
+							   0xe0, val|0x80 };
+
+					assert(s->vkbd != -1);
+					write(s->vkbd, buf, sizeof(buf));
+				} else
+					syslog(LOG_ERR, "Keyboard events " \
+						"received from non-keyboard " \
+						"device %s. Please report",
+						bt_ntoa(&s->bdaddr, NULL));
+			}
+			break;
+
+		case HUP_MICROSOFT:
+			switch (usage) {
+			case 0xfe01:
+				if (!hid_device->battery_power)
+					break;
+
+				switch (val) {
+				case 1:
+					syslog(LOG_INFO, "Battery is OK on %s",
+						bt_ntoa(&s->bdaddr, NULL));
+					break;
+
+				case 2:
+					syslog(LOG_NOTICE, "Low battery on %s",
+						bt_ntoa(&s->bdaddr, NULL));
+					break;
+
+				case 3:
+					syslog(LOG_WARNING, "Very low battery "\
+                                                "on %s",
+						bt_ntoa(&s->bdaddr, NULL));
+					break;
+                                }
+				break;
+			}
+			break;
+		}
+	}
+	hid_end_parse(d);
+
+	/*
+	 * XXX FIXME Feed keyboard events into kernel.
+	 * The code below works, bit host also needs to track
+	 * and handle repeat.
+	 *
+	 * Key repeat currently works in X, but not in console.
+	 */
+
+	if (kevents > 0) {
+		if (hid_device->keyboard) {
+			assert(s->vkbd != -1);
+			kbd_process_keys(s);
+		} else
+			syslog(LOG_ERR, "Keyboard events received from " \
+				"non-keyboard device %s. Please report",
+				bt_ntoa(&s->bdaddr, NULL));
+	}
+
+	/* 
+	 * XXX FIXME Feed mouse events into kernel.
+	 * The code block below works, but it is not good enough.
+	 * Need to track double-clicks etc.
+	 *
+	 * Double click currently works in X, but not in console.
+	 */
+
+	if (mevents > 0) {
+		struct mouse_info	mi;
+
+		mi.operation = MOUSE_ACTION;
+		mi.u.data.x = mouse_x;
+		mi.u.data.y = mouse_y;
+		mi.u.data.z = mouse_z;
+		mi.u.data.buttons = mouse_butt;
+
+		if (ioctl(s->srv->cons, CONS_MOUSECTL, &mi) < 0)
+			syslog(LOG_ERR, "Could not process mouse events from " \
+				"%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
+				strerror(errno), errno);
+	}
+
+	return (0);
+}
diff --git a/usr.sbin/bthidd/kbd.c b/usr.sbin/bthidd/kbd.c
new file mode 100644
index 0000000000..a9a7132d66
--- /dev/null
+++ b/usr.sbin/bthidd/kbd.c
@@ -0,0 +1,580 @@
+/*
+ * kbd.c
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: kbd.c,v 1.4 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/kbd.c 258780 2013-11-30 22:17:27Z eadler $
+ */
+
+#include <sys/consio.h>
+#include <sys/ioctl.h>
+#include <sys/kbio.h>
+#include <sys/queue.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usbhid.h>
+#include <dev/vkbd/vkbd_var.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <usbhid.h>
+#include "bthid_config.h"
+#include "bthidd.h"
+#include "kbd.h"
+
+static void	kbd_write(bitstr_t *m, int32_t fb, int32_t make, int32_t fd);
+static int32_t	kbd_xlate(int32_t code, int32_t make, int32_t *b, int32_t const *eob);
+
+/*
+ * HID code to PS/2 set 1 code translation table.
+ *
+ * http://www.microsoft.com/whdc/device/input/Scancode.mspx
+ *
+ * The table only contains "make" (key pressed) codes.
+ * The "break" (key released) code is generated as "make" | 0x80
+ */
+
+#define E0PREFIX	(1U << 31)
+#define NOBREAK		(1 << 30)
+#define CODEMASK	(~(E0PREFIX|NOBREAK))
+
+static int32_t const	x[] =
+{
+/*==================================================*/
+/* Name                   HID code    Make     Break*/
+/*==================================================*/
+/* No Event                     00 */ -1,   /* None */
+/* Overrun Error                01 */ NOBREAK|0xFF, /* None */
+/* POST Fail                    02 */ NOBREAK|0xFC, /* None */
+/* ErrorUndefined               03 */ -1,   /* Unassigned */
+/* a A                          04 */ 0x1E, /* 9E */
+/* b B                          05 */ 0x30, /* B0 */
+/* c C                          06 */ 0x2E, /* AE */
+/* d D                          07 */ 0x20, /* A0 */
+/* e E                          08 */ 0x12, /* 92 */
+/* f F                          09 */ 0x21, /* A1 */
+/* g G                          0A */ 0x22, /* A2 */
+/* h H                          0B */ 0x23, /* A3 */
+/* i I                          0C */ 0x17, /* 97 */
+/* j J                          0D */ 0x24, /* A4 */
+/* k K                          0E */ 0x25, /* A5 */
+/* l L                          0F */ 0x26, /* A6 */
+/* m M                          10 */ 0x32, /* B2 */
+/* n N                          11 */ 0x31, /* B1 */
+/* o O                          12 */ 0x18, /* 98 */
+/* p P                          13 */ 0x19, /* 99 */
+/* q Q                          14 */ 0x10, /* 90 */
+/* r R                          15 */ 0x13, /* 93 */
+/* s S                          16 */ 0x1F, /* 9F */
+/* t T                          17 */ 0x14, /* 94 */
+/* u U                          18 */ 0x16, /* 96 */
+/* v V                          19 */ 0x2F, /* AF */
+/* w W                          1A */ 0x11, /* 91 */
+/* x X                          1B */ 0x2D, /* AD */
+/* y Y                          1C */ 0x15, /* 95 */
+/* z Z                          1D */ 0x2C, /* AC */
+/* 1 !                          1E */ 0x02, /* 82 */
+/* 2 @                          1F */ 0x03, /* 83 */
+/* 3 #                          20 */ 0x04, /* 84 */
+/* 4 $                          21 */ 0x05, /* 85 */
+/* 5 %                          22 */ 0x06, /* 86 */
+/* 6 ^                          23 */ 0x07, /* 87 */
+/* 7 &                          24 */ 0x08, /* 88 */
+/* 8 *                          25 */ 0x09, /* 89 */
+/* 9 (                          26 */ 0x0A, /* 8A */
+/* 0 )                          27 */ 0x0B, /* 8B */
+/* Return                       28 */ 0x1C, /* 9C */
+/* Escape                       29 */ 0x01, /* 81 */
+/* Backspace                    2A */ 0x0E, /* 8E */
+/* Tab                          2B */ 0x0F, /* 8F */
+/* Space                        2C */ 0x39, /* B9 */
+/* - _                          2D */ 0x0C, /* 8C */
+/* = +                          2E */ 0x0D, /* 8D */
+/* [ {                          2F */ 0x1A, /* 9A */
+/* ] }                          30 */ 0x1B, /* 9B */
+/* \ |                          31 */ 0x2B, /* AB */
+/* Europe 1                     32 */ 0x2B, /* AB */
+/* ; :                          33 */ 0x27, /* A7 */
+/* " '                          34 */ 0x28, /* A8 */
+/* ` ~                          35 */ 0x29, /* A9 */
+/* comma <                      36 */ 0x33, /* B3 */
+/* . >                          37 */ 0x34, /* B4 */
+/* / ?                          38 */ 0x35, /* B5 */
+/* Caps Lock                    39 */ 0x3A, /* BA */
+/* F1                           3A */ 0x3B, /* BB */
+/* F2                           3B */ 0x3C, /* BC */
+/* F3                           3C */ 0x3D, /* BD */
+/* F4                           3D */ 0x3E, /* BE */
+/* F5                           3E */ 0x3F, /* BF */
+/* F6                           3F */ 0x40, /* C0 */
+/* F7                           40 */ 0x41, /* C1 */
+/* F8                           41 */ 0x42, /* C2 */
+/* F9                           42 */ 0x43, /* C3 */
+/* F10                          43 */ 0x44, /* C4 */
+/* F11                          44 */ 0x57, /* D7 */
+/* F12                          45 */ 0x58, /* D8 */
+/* Print Screen                 46 */ E0PREFIX|0x37, /* E0 B7 */
+/* Scroll Lock                  47 */ 0x46, /* C6 */
+#if 0
+/* Break (Ctrl-Pause)           48 */ E0 46 E0 C6, /* None */
+/* Pause                        48 */ E1 1D 45 E1 9D C5, /* None */
+#else
+/* Break (Ctrl-Pause)/Pause     48 */ NOBREAK /* Special case */, /* None */
+#endif
+/* Insert                       49 */ E0PREFIX|0x52, /* E0 D2 */
+/* Home                         4A */ E0PREFIX|0x47, /* E0 C7 */
+/* Page Up                      4B */ E0PREFIX|0x49, /* E0 C9 */
+/* Delete                       4C */ E0PREFIX|0x53, /* E0 D3 */
+/* End                          4D */ E0PREFIX|0x4F, /* E0 CF */
+/* Page Down                    4E */ E0PREFIX|0x51, /* E0 D1 */
+/* Right Arrow                  4F */ E0PREFIX|0x4D, /* E0 CD */
+/* Left Arrow                   50 */ E0PREFIX|0x4B, /* E0 CB */
+/* Down Arrow                   51 */ E0PREFIX|0x50, /* E0 D0 */
+/* Up Arrow                     52 */ E0PREFIX|0x48, /* E0 C8 */
+/* Num Lock                     53 */ 0x45, /* C5 */
+/* Keypad /                     54 */ E0PREFIX|0x35, /* E0 B5 */
+/* Keypad *                     55 */ 0x37, /* B7 */
+/* Keypad -                     56 */ 0x4A, /* CA */
+/* Keypad +                     57 */ 0x4E, /* CE */
+/* Keypad Enter                 58 */ E0PREFIX|0x1C, /* E0 9C */
+/* Keypad 1 End                 59 */ 0x4F, /* CF */
+/* Keypad 2 Down                5A */ 0x50, /* D0 */
+/* Keypad 3 PageDn              5B */ 0x51, /* D1 */
+/* Keypad 4 Left                5C */ 0x4B, /* CB */
+/* Keypad 5                     5D */ 0x4C, /* CC */
+/* Keypad 6 Right               5E */ 0x4D, /* CD */
+/* Keypad 7 Home                5F */ 0x47, /* C7 */
+/* Keypad 8 Up                  60 */ 0x48, /* C8 */
+/* Keypad 9 PageUp              61 */ 0x49, /* C9 */
+/* Keypad 0 Insert              62 */ 0x52, /* D2 */
+/* Keypad . Delete              63 */ 0x53, /* D3 */
+/* Europe 2                     64 */ 0x56, /* D6 */
+/* App                          65 */ E0PREFIX|0x5D, /* E0 DD */
+/* Keyboard Power               66 */ E0PREFIX|0x5E, /* E0 DE */
+/* Keypad =                     67 */ 0x59, /* D9 */
+/* F13                          68 */ 0x64, /* E4 */
+/* F14                          69 */ 0x65, /* E5 */
+/* F15                          6A */ 0x66, /* E6 */
+/* F16                          6B */ 0x67, /* E7 */
+/* F17                          6C */ 0x68, /* E8 */
+/* F18                          6D */ 0x69, /* E9 */
+/* F19                          6E */ 0x6A, /* EA */
+/* F20                          6F */ 0x6B, /* EB */
+/* F21                          70 */ 0x6C, /* EC */
+/* F22                          71 */ 0x6D, /* ED */
+/* F23                          72 */ 0x6E, /* EE */
+/* F24                          73 */ 0x76, /* F6 */
+/* Keyboard Execute             74 */ -1,   /* Unassigned */
+/* Keyboard Help                75 */ -1,   /* Unassigned */
+/* Keyboard Menu                76 */ -1,   /* Unassigned */
+/* Keyboard Select              77 */ -1,   /* Unassigned */
+/* Keyboard Stop                78 */ -1,   /* Unassigned */
+/* Keyboard Again               79 */ -1,   /* Unassigned */
+/* Keyboard Undo                7A */ -1,   /* Unassigned */
+/* Keyboard Cut                 7B */ -1,   /* Unassigned */
+/* Keyboard Copy                7C */ -1,   /* Unassigned */
+/* Keyboard Paste               7D */ -1,   /* Unassigned */
+/* Keyboard Find                7E */ -1,   /* Unassigned */
+/* Keyboard Mute                7F */ -1,   /* Unassigned */
+/* Keyboard Volume Up           80 */ -1,   /* Unassigned */
+/* Keyboard Volume Dn           81 */ -1,   /* Unassigned */
+/* Keyboard Locking Caps Lock   82 */ -1,   /* Unassigned */
+/* Keyboard Locking Num Lock    83 */ -1,   /* Unassigned */
+/* Keyboard Locking Scroll Lock 84 */ -1,   /* Unassigned */
+/* Keypad comma                 85 */ 0x7E, /* FE */
+/* Keyboard Equal Sign          86 */ -1,   /* Unassigned */
+/* Keyboard Int'l 1             87 */ 0x73, /* F3 */
+/* Keyboard Int'l 2             88 */ 0x70, /* F0 */
+/* Keyboard Int'l 2             89 */ 0x7D, /* FD */
+/* Keyboard Int'l 4             8A */ 0x79, /* F9 */
+/* Keyboard Int'l 5             8B */ 0x7B, /* FB */
+/* Keyboard Int'l 6             8C */ 0x5C, /* DC */
+/* Keyboard Int'l 7             8D */ -1,   /* Unassigned */
+/* Keyboard Int'l 8             8E */ -1,   /* Unassigned */
+/* Keyboard Int'l 9             8F */ -1,   /* Unassigned */
+/* Keyboard Lang 1              90 */ NOBREAK|0xF2, /* None */
+/* Keyboard Lang 2              91 */ NOBREAK|0xF1, /* None */
+/* Keyboard Lang 3              92 */ 0x78, /* F8 */
+/* Keyboard Lang 4              93 */ 0x77, /* F7 */
+/* Keyboard Lang 5              94 */ 0x76, /* F6 */
+/* Keyboard Lang 6              95 */ -1,   /* Unassigned */
+/* Keyboard Lang 7              96 */ -1,   /* Unassigned */
+/* Keyboard Lang 8              97 */ -1,   /* Unassigned */
+/* Keyboard Lang 9              98 */ -1,   /* Unassigned */
+/* Keyboard Alternate Erase     99 */ -1,   /* Unassigned */
+/* Keyboard SysReq/Attention    9A */ -1,   /* Unassigned */
+/* Keyboard Cancel              9B */ -1,   /* Unassigned */
+/* Keyboard Clear               9C */ -1,   /* Unassigned */
+/* Keyboard Prior               9D */ -1,   /* Unassigned */
+/* Keyboard Return              9E */ -1,   /* Unassigned */
+/* Keyboard Separator           9F */ -1,   /* Unassigned */
+/* Keyboard Out                 A0 */ -1,   /* Unassigned */
+/* Keyboard Oper                A1 */ -1,   /* Unassigned */
+/* Keyboard Clear/Again         A2 */ -1,   /* Unassigned */
+/* Keyboard CrSel/Props         A3 */ -1,   /* Unassigned */
+/* Keyboard ExSel               A4 */ -1,   /* Unassigned */
+/* Reserved                     A5 */ -1,   /* Reserved */
+/* Reserved                     A6 */ -1,   /* Reserved */
+/* Reserved                     A7 */ -1,   /* Reserved */
+/* Reserved                     A8 */ -1,   /* Reserved */
+/* Reserved                     A9 */ -1,   /* Reserved */
+/* Reserved                     AA */ -1,   /* Reserved */
+/* Reserved                     AB */ -1,   /* Reserved */
+/* Reserved                     AC */ -1,   /* Reserved */
+/* Reserved                     AD */ -1,   /* Reserved */
+/* Reserved                     AE */ -1,   /* Reserved */
+/* Reserved                     AF */ -1,   /* Reserved */
+/* Reserved                     B0 */ -1,   /* Reserved */
+/* Reserved                     B1 */ -1,   /* Reserved */
+/* Reserved                     B2 */ -1,   /* Reserved */
+/* Reserved                     B3 */ -1,   /* Reserved */
+/* Reserved                     B4 */ -1,   /* Reserved */
+/* Reserved                     B5 */ -1,   /* Reserved */
+/* Reserved                     B6 */ -1,   /* Reserved */
+/* Reserved                     B7 */ -1,   /* Reserved */
+/* Reserved                     B8 */ -1,   /* Reserved */
+/* Reserved                     B9 */ -1,   /* Reserved */
+/* Reserved                     BA */ -1,   /* Reserved */
+/* Reserved                     BB */ -1,   /* Reserved */
+/* Reserved                     BC */ -1,   /* Reserved */
+/* Reserved                     BD */ -1,   /* Reserved */
+/* Reserved                     BE */ -1,   /* Reserved */
+/* Reserved                     BF */ -1,   /* Reserved */
+/* Reserved                     C0 */ -1,   /* Reserved */
+/* Reserved                     C1 */ -1,   /* Reserved */
+/* Reserved                     C2 */ -1,   /* Reserved */
+/* Reserved                     C3 */ -1,   /* Reserved */
+/* Reserved                     C4 */ -1,   /* Reserved */
+/* Reserved                     C5 */ -1,   /* Reserved */
+/* Reserved                     C6 */ -1,   /* Reserved */
+/* Reserved                     C7 */ -1,   /* Reserved */
+/* Reserved                     C8 */ -1,   /* Reserved */
+/* Reserved                     C9 */ -1,   /* Reserved */
+/* Reserved                     CA */ -1,   /* Reserved */
+/* Reserved                     CB */ -1,   /* Reserved */
+/* Reserved                     CC */ -1,   /* Reserved */
+/* Reserved                     CD */ -1,   /* Reserved */
+/* Reserved                     CE */ -1,   /* Reserved */
+/* Reserved                     CF */ -1,   /* Reserved */
+/* Reserved                     D0 */ -1,   /* Reserved */
+/* Reserved                     D1 */ -1,   /* Reserved */
+/* Reserved                     D2 */ -1,   /* Reserved */
+/* Reserved                     D3 */ -1,   /* Reserved */
+/* Reserved                     D4 */ -1,   /* Reserved */
+/* Reserved                     D5 */ -1,   /* Reserved */
+/* Reserved                     D6 */ -1,   /* Reserved */
+/* Reserved                     D7 */ -1,   /* Reserved */
+/* Reserved                     D8 */ -1,   /* Reserved */
+/* Reserved                     D9 */ -1,   /* Reserved */
+/* Reserved                     DA */ -1,   /* Reserved */
+/* Reserved                     DB */ -1,   /* Reserved */
+/* Reserved                     DC */ -1,   /* Reserved */
+/* Reserved                     DD */ -1,   /* Reserved */
+/* Reserved                     DE */ -1,   /* Reserved */
+/* Reserved                     DF */ -1,   /* Reserved */
+/* Left Control                 E0 */ 0x1D, /* 9D */
+/* Left Shift                   E1 */ 0x2A, /* AA */
+/* Left Alt                     E2 */ 0x38, /* B8 */
+/* Left GUI                     E3 */ E0PREFIX|0x5B, /* E0 DB */
+/* Right Control                E4 */ E0PREFIX|0x1D, /* E0 9D */
+/* Right Shift                  E5 */ 0x36, /* B6 */
+/* Right Alt                    E6 */ E0PREFIX|0x38, /* E0 B8 */
+/* Right GUI                    E7 */ E0PREFIX|0x5C  /* E0 DC */
+};
+
+#define xsize	((int32_t)(sizeof(x)/sizeof(x[0])))
+
+/*
+ * Get a max HID keycode (aligned)
+ */
+
+int32_t
+kbd_maxkey(void)
+{
+	return (xsize);
+}
+
+/*
+ * Process keys
+ */
+
+int32_t
+kbd_process_keys(bthid_session_p s)
+{
+	bitstr_t	diff[bitstr_size(xsize)];
+	int32_t		f1, f2, i;
+
+	assert(s != NULL);
+	assert(s->srv != NULL);
+
+	/* Check if the new keys have been pressed */
+	bit_ffs(s->keys1, xsize, &f1);
+
+	/* Check if old keys still pressed */
+	bit_ffs(s->keys2, xsize, &f2);
+
+	if (f1 == -1) {
+		/* no new key pressed */
+		if (f2 != -1) {
+			/* release old keys */
+			kbd_write(s->keys2, f2, 0, s->vkbd);
+			memset(s->keys2, 0, bitstr_size(xsize));
+		}
+
+		return (0);
+	}
+
+	if (f2 == -1) {
+		/* no old keys, but new keys pressed */
+		assert(f1 != -1);
+		
+		memcpy(s->keys2, s->keys1, bitstr_size(xsize));
+		kbd_write(s->keys1, f1, 1, s->vkbd);
+		memset(s->keys1, 0, bitstr_size(xsize));
+
+		return (0);
+	}
+
+	/* new keys got pressed, old keys got released */
+	memset(diff, 0, bitstr_size(xsize));
+
+	for (i = f2; i < xsize; i ++) {
+		if (bit_test(s->keys2, i)) {
+			if (!bit_test(s->keys1, i)) {
+				bit_clear(s->keys2, i);
+				bit_set(diff, i);
+			}
+		}
+	}
+
+	for (i = f1; i < xsize; i++) {
+		if (bit_test(s->keys1, i)) {
+			if (!bit_test(s->keys2, i))
+				bit_set(s->keys2, i);
+			else
+				bit_clear(s->keys1, i);
+		}
+	}
+
+	bit_ffs(diff, xsize, &f2);
+	if (f2 > 0)
+		kbd_write(diff, f2, 0, s->vkbd);
+
+	bit_ffs(s->keys1, xsize, &f1);
+	if (f1 > 0) {
+		kbd_write(s->keys1, f1, 1, s->vkbd);
+		memset(s->keys1, 0, bitstr_size(xsize));
+	}
+
+	return (0);
+}
+
+/*
+ * Translate given keymap and write keyscodes
+ */ 
+
+static void
+kbd_write(bitstr_t *m, int32_t fb, int32_t make, int32_t fd)
+{
+	int32_t	i, *b, *eob, n, buf[64];
+
+	b = buf;
+	eob = b + sizeof(buf)/sizeof(buf[0]);
+	i = fb;
+
+	while (i < xsize) {
+		if (bit_test(m, i)) {
+			n = kbd_xlate(i, make, b, eob);
+			if (n == -1) {
+				write(fd, buf, (b - buf) * sizeof(buf[0]));
+				b = buf;
+				continue;
+			}
+
+			b += n;
+		}
+
+		i ++;
+	}
+
+	if (b != buf)
+		write(fd, buf, (b - buf) * sizeof(buf[0]));
+}
+
+/*
+ * Translate HID code into PS/2 code and put codes into buffer b.
+ * Returns the number of codes put in b. Return -1 if buffer has not
+ * enough space.
+ */
+
+#undef  PUT
+#define PUT(c, n, b, eob)	\
+do {				\
+	if ((b) >= (eob))	\
+		return (-1);	\
+	*(b) = (c);		\
+	(b) ++;			\
+	(n) ++;			\
+} while (0)
+
+static int32_t
+kbd_xlate(int32_t code, int32_t make, int32_t *b, int32_t const *eob)
+{
+	int32_t	c, n;
+
+	n = 0;
+
+	if (code >= xsize)
+		return (0); /* HID code is not in the table */
+
+	/* Handle special case - Pause/Break */
+	if (code == 0x48) {
+		if (!make)
+			return (0); /* No break code */
+
+#if 0
+XXX FIXME
+		if (ctrl_is_pressed) {
+			/* Break (Ctrl-Pause) */
+			PUT(0xe0, n, b, eob);
+			PUT(0x46, n, b, eob);
+			PUT(0xe0, n, b, eob);
+			PUT(0xc6, n, b, eob);
+		} else {
+			/* Pause */
+			PUT(0xe1, n, b, eob);
+			PUT(0x1d, n, b, eob);
+			PUT(0x45, n, b, eob);
+			PUT(0xe1, n, b, eob);
+			PUT(0x9d, n, b, eob);
+			PUT(0xc5, n, b, eob);
+		}
+#endif
+
+		return (n);
+	}
+
+	if ((c = x[code]) == -1)
+		return (0); /* HID code translation is not defined */
+
+	if (make) {
+		if (c & E0PREFIX)
+			PUT(0xe0, n, b, eob);
+
+		PUT((c & CODEMASK), n, b, eob);
+	} else if (!(c & NOBREAK)) {
+		if (c & E0PREFIX)
+			PUT(0xe0, n, b, eob);
+
+		PUT((0x80|(c & CODEMASK)), n, b, eob);
+	}
+
+	return (n);
+}
+
+/*
+ * Process status change from vkbd(4)
+ */
+
+int32_t
+kbd_status_changed(bthid_session_p s, uint8_t *data, int32_t len)
+{
+	vkbd_status_t	st;
+	uint8_t		leds, report_id;
+	hid_device_p	hid_device;
+	hid_data_t	d;
+	hid_item_t	h;
+
+	assert(s != NULL);
+	assert(len == sizeof(vkbd_status_t));
+
+	memcpy(&st, data, sizeof(st));
+	leds = 0;
+	report_id = NO_REPORT_ID;
+
+	hid_device = get_hid_device(&s->bdaddr);
+	assert(hid_device != NULL);
+
+	for (d = hid_start_parse(hid_device->desc, 1 << hid_output, -1);
+	     hid_get_item(d, &h) > 0; ) {
+		if (HID_PAGE(h.usage) == HUP_LEDS) {
+			if (report_id == NO_REPORT_ID)
+				report_id = h.report_ID;
+			else if (h.report_ID != report_id)
+				syslog(LOG_WARNING, "Output HID report IDs " \
+					"for %s do not match: %d vs. %d. " \
+					"Please report",
+					bt_ntoa(&s->bdaddr, NULL),
+					h.report_ID, report_id);
+			
+			switch(HID_USAGE(h.usage)) {
+			case 0x01: /* Num Lock LED */
+				if (st.leds & LED_NUM)
+					hid_set_data(&leds, &h, 1);
+				break;
+
+			case 0x02: /* Caps Lock LED */
+				if (st.leds & LED_CAP)
+					hid_set_data(&leds, &h, 1);
+				break;
+
+			case 0x03: /* Scroll Lock LED */
+				if (st.leds & LED_SCR)
+					hid_set_data(&leds, &h, 1);
+				break;
+
+			/* XXX add other LEDs ? */
+			}
+		}
+	}
+	hid_end_parse(d);
+
+	data[0] = 0xa2; /* DATA output (HID output report) */
+
+	if (report_id != NO_REPORT_ID) {
+		data[1] = report_id;
+		data[2] = leds;
+		len = 3;
+	} else {
+		data[1] = leds;
+		len = 2;
+	}
+
+	write(s->intr, data, len);
+
+	return (0);
+}
+
diff --git a/usr.sbin/bthidd/kbd.h b/usr.sbin/bthidd/kbd.h
new file mode 100644
index 0000000000..b30bba86c3
--- /dev/null
+++ b/usr.sbin/bthidd/kbd.h
@@ -0,0 +1,41 @@
+/*
+ * kbd.h
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: kbd.h,v 1.3 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/kbd.h 162128 2006-09-07 21:47:49Z emax $
+ */
+
+#ifndef _KBD_H_
+#define _KBD_H_
+
+int32_t	kbd_maxkey	  (void);
+int32_t	kbd_process_keys  (bthid_session_p s);
+int32_t	kbd_status_changed(bthid_session_p s, uint8_t *data, int32_t len);
+
+#endif /* ndef _KBD_H_ */
diff --git a/usr.sbin/bthidd/lexer.l b/usr.sbin/bthidd/lexer.l
new file mode 100644
index 0000000000..667e2848b5
--- /dev/null
+++ b/usr.sbin/bthidd/lexer.l
@@ -0,0 +1,106 @@
+%{
+/*
+ * lexer.l
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: lexer.l,v 1.3 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/lexer.l 250926 2013-05-23 05:42:35Z jkim $
+ */
+
+#include <bluetooth.h>
+#include <stdlib.h>
+#include "parser.h"
+
+	int	yylex	(void);
+
+#define	YY_DECL	int yylex(void)
+%}
+
+%option yylineno noyywrap nounput noinput
+
+delim				[ \t\n]
+ws				{delim}+
+empty				{delim}*
+comment				\#.*
+
+hexdigit			[0-9a-fA-F]
+hexbyte				{hexdigit}{hexdigit}?
+
+device_word			device
+bdaddr_word			bdaddr
+control_psm_word		control_psm
+interrupt_psm_word		interrupt_psm
+reconnect_initiate_word		reconnect_initiate
+battery_power_word		battery_power
+normally_connectable_word	normally_connectable
+hid_descriptor_word		hid_descriptor
+true_word			true
+false_word			false
+
+bdaddrstring			{hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}
+hexbytestring			0x{hexbyte}
+
+%%
+
+\;				return (';');
+\:				return (':');
+\{				return ('{');
+\}				return ('}');
+
+{ws}				;
+{empty}				;
+{comment}			;
+
+{device_word}			return (T_DEVICE);
+{bdaddr_word}			return (T_BDADDR);
+{control_psm_word}		return (T_CONTROL_PSM);
+{interrupt_psm_word}		return (T_INTERRUPT_PSM);
+{reconnect_initiate_word}	return (T_RECONNECT_INITIATE);
+{battery_power_word}		return (T_BATTERY_POWER);
+{normally_connectable_word}	return (T_NORMALLY_CONNECTABLE);
+{hid_descriptor_word}		return (T_HID_DESCRIPTOR);
+{true_word}			return (T_TRUE);
+{false_word}			return (T_FALSE);
+
+{bdaddrstring}			{
+				return (bt_aton(yytext, &yylval.bdaddr)?
+						T_BDADDRSTRING : T_ERROR);
+				}
+
+{hexbytestring}			{
+				char	*ep;
+
+				yylval.num = strtoul(yytext, &ep, 16);
+
+				return (*ep == '\0'? T_HEXBYTE : T_ERROR);
+				}
+
+.				return (T_ERROR);
+
+%%
+
diff --git a/usr.sbin/bthidd/parser.y b/usr.sbin/bthidd/parser.y
new file mode 100644
index 0000000000..8ff9206add
--- /dev/null
+++ b/usr.sbin/bthidd/parser.y
@@ -0,0 +1,475 @@
+%{
+/*
+ * parser.y
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: parser.y,v 1.7 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/parser.y 235789 2012-05-22 16:33:10Z bapt $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usbhid.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <usbhid.h>
+
+#ifndef BTHIDCONTROL
+#include <stdarg.h>
+#include <syslog.h>
+#define	SYSLOG		syslog
+#define	LOGCRIT		LOG_CRIT
+#define	LOGERR		LOG_ERR
+#define	LOGWARNING	LOG_WARNING
+#define	EOL
+#else
+#define	SYSLOG		fprintf
+#define	LOGCRIT		stderr
+#define	LOGERR		stderr
+#define	LOGWARNING	stderr
+#define	EOL	"\n"
+#endif /* ndef BTHIDCONTROL */
+
+#include "bthid_config.h"
+
+	int	yylex		(void);
+	void	yyerror		(char const *);
+static	int32_t	check_hid_device(hid_device_p hid_device);
+static	void	free_hid_device	(hid_device_p hid_device);
+
+extern	FILE			*yyin;
+extern	int			 yylineno;
+	char const		*config_file = BTHIDD_CONFFILE;
+	char const		*hids_file   = BTHIDD_HIDSFILE;
+
+static	char			 buffer[1024];
+static	int32_t			 hid_descriptor_size;
+static	hid_device_t		*hid_device = NULL;
+static	LIST_HEAD(, hid_device)	 hid_devices;
+
+%}
+
+%union {
+	bdaddr_t	bdaddr;
+	int32_t		num;
+}
+
+%token <bdaddr> T_BDADDRSTRING
+%token <num>	T_HEXBYTE
+%token T_DEVICE T_BDADDR T_CONTROL_PSM T_INTERRUPT_PSM T_RECONNECT_INITIATE
+%token T_BATTERY_POWER T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR
+%token T_TRUE T_FALSE T_ERROR
+
+%%
+
+config:		line
+		| config line
+		;
+
+line:		T_DEVICE
+			{
+			hid_device = (hid_device_t *) calloc(1, sizeof(*hid_device));
+			if (hid_device == NULL) {
+				SYSLOG(LOGCRIT, "Could not allocate new " \
+						"config entry" EOL);
+				YYABORT;
+			}
+
+			hid_device->new_device = 1;
+			}
+		'{' options '}'
+			{
+			if (check_hid_device(hid_device))
+				LIST_INSERT_HEAD(&hid_devices,hid_device,next);
+			else
+				free_hid_device(hid_device);
+
+			hid_device = NULL;
+			}
+		;
+
+options:	option ';'
+		| options option ';'
+		;
+
+option:		bdaddr
+		| control_psm
+		| interrupt_psm
+		| reconnect_initiate
+		| battery_power
+		| normally_connectable
+		| hid_descriptor
+		| parser_error
+		;
+
+bdaddr:		T_BDADDR T_BDADDRSTRING
+			{
+			memcpy(&hid_device->bdaddr, &$2, sizeof(hid_device->bdaddr));
+			}
+		;
+
+control_psm:	T_CONTROL_PSM T_HEXBYTE
+			{
+			hid_device->control_psm = $2;
+			}
+		;
+
+interrupt_psm:	T_INTERRUPT_PSM T_HEXBYTE
+			{
+			hid_device->interrupt_psm = $2;
+			}
+		;
+
+reconnect_initiate: T_RECONNECT_INITIATE T_TRUE
+			{
+			hid_device->reconnect_initiate = 1;
+			}
+		| T_RECONNECT_INITIATE T_FALSE
+			{
+			hid_device->reconnect_initiate = 0;
+			}
+		;
+
+battery_power:	T_BATTERY_POWER T_TRUE
+			{
+			hid_device->battery_power = 1;
+			}
+		| T_BATTERY_POWER T_FALSE
+			{
+			hid_device->battery_power = 0;
+			}
+		;
+
+normally_connectable: T_NORMALLY_CONNECTABLE T_TRUE
+			{
+			hid_device->normally_connectable = 1;
+			}
+		| T_NORMALLY_CONNECTABLE T_FALSE
+			{
+			hid_device->normally_connectable = 0;
+			}
+		;
+
+hid_descriptor:	T_HID_DESCRIPTOR	
+			{
+			hid_descriptor_size = 0;
+			}
+		'{' hid_descriptor_bytes '}'
+			{
+			if (hid_device->desc != NULL)
+				hid_dispose_report_desc(hid_device->desc);
+
+			hid_device->desc = hid_use_report_desc((unsigned char *) buffer, hid_descriptor_size);
+			if (hid_device->desc == NULL) {
+				SYSLOG(LOGCRIT, "Could not use HID descriptor" EOL);
+				YYABORT;
+			}
+			}
+		;
+
+hid_descriptor_bytes: hid_descriptor_byte
+		| hid_descriptor_bytes hid_descriptor_byte
+		;
+
+hid_descriptor_byte: T_HEXBYTE
+			{
+			if (hid_descriptor_size >= (int32_t) sizeof(buffer)) {
+				SYSLOG(LOGCRIT, "HID descriptor is too big" EOL);
+				YYABORT;
+			}
+
+			buffer[hid_descriptor_size ++] = $1;
+			}
+		;
+
+parser_error:	T_ERROR
+			{
+				YYABORT;
+			}
+
+%%
+
+/* Display parser error message */
+void
+yyerror(char const *message)
+{
+	SYSLOG(LOGERR, "%s in line %d" EOL, message, yylineno); 
+}
+
+/* Re-read config file */
+int32_t
+read_config_file(void)
+{
+	int32_t	e;
+
+	if (config_file == NULL) {
+		SYSLOG(LOGERR, "Unknown config file name!" EOL);
+		return (-1);
+	}
+
+	if ((yyin = fopen(config_file, "r")) == NULL) {
+		SYSLOG(LOGERR, "Could not open config file '%s'. %s (%d)" EOL,
+				config_file, strerror(errno), errno);
+		return (-1);
+	}
+
+	clean_config();
+	if (yyparse() < 0) {
+		SYSLOG(LOGERR, "Could not parse config file '%s'" EOL,
+				config_file);
+		e = -1;
+	} else
+		e = 0;
+
+	fclose(yyin);
+	yyin = NULL;
+
+	return (e);
+}
+
+/* Clean config */
+void
+clean_config(void)
+{
+	while (!LIST_EMPTY(&hid_devices)) {
+		hid_device_p	d = LIST_FIRST(&hid_devices);
+
+		LIST_REMOVE(d, next);
+		free_hid_device(d);
+	}
+}
+
+/* Lookup config entry */
+hid_device_p
+get_hid_device(bdaddr_p bdaddr)
+{
+	hid_device_p	d;
+
+	LIST_FOREACH(d, &hid_devices, next)
+		if (memcmp(&d->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
+			break;
+
+	return (d);
+}
+
+/* Get next config entry */
+hid_device_p
+get_next_hid_device(hid_device_p d)
+{
+	return ((d == NULL)? LIST_FIRST(&hid_devices) : LIST_NEXT(d, next));
+}
+
+/* Print config entry */
+void
+print_hid_device(hid_device_p d, FILE *f)
+{
+	/* XXX FIXME hack! */
+	struct report_desc {
+		unsigned int	size;
+		unsigned char	data[1];
+	};
+	/* XXX FIXME hack! */
+
+	struct report_desc	*desc = (struct report_desc *) d->desc;
+	uint32_t		 i;
+
+	fprintf(f,
+"device {\n"					\
+"	bdaddr			%s;\n"		\
+"	control_psm		0x%x;\n"	\
+"	interrupt_psm		0x%x;\n"	\
+"	reconnect_initiate	%s;\n"		\
+"	battery_power		%s;\n"		\
+"	normally_connectable	%s;\n"		\
+"	hid_descriptor		{",
+		bt_ntoa(&d->bdaddr, NULL),
+		d->control_psm, d->interrupt_psm,
+                d->reconnect_initiate? "true" : "false",
+                d->battery_power? "true" : "false",
+                d->normally_connectable? "true" : "false");
+ 
+	for (i = 0; i < desc->size; i ++) {
+			if ((i % 8) == 0)
+				fprintf(f, "\n		");
+ 
+			fprintf(f, "0x%2.2x ", desc->data[i]);
+	}
+                
+	fprintf(f,
+"\n"		\
+"	};\n"	\
+"}\n");
+}
+
+/* Check config entry */
+static int32_t
+check_hid_device(hid_device_p d)
+{
+	hid_data_t	hd;
+	hid_item_t	hi;
+	int32_t		page;
+
+	if (get_hid_device(&d->bdaddr) != NULL) {
+		SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL,
+				bt_ntoa(&d->bdaddr, NULL));
+		return (0);
+	}
+
+	if (d->control_psm == 0) {
+		SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL);
+		return (0);
+	}
+
+	if (d->interrupt_psm == 0) {
+		SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL);
+		return (0);
+	}
+
+	if (d->desc == NULL) {
+		SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL);
+		return (0);
+	}
+
+	/* XXX somehow need to make sure descriptor is valid */
+	for (hd = hid_start_parse(d->desc, ~0, -1); hid_get_item(hd, &hi) > 0; ) {
+		switch (hi.kind) {
+		case hid_collection:
+		case hid_endcollection:
+		case hid_output:
+		case hid_feature:
+			break;
+
+		case hid_input:
+			/* Check if the device may send keystrokes */
+			page = HID_PAGE(hi.usage);
+			if (page == HUP_KEYBOARD)
+				d->keyboard = 1;
+			break;
+		}
+	}
+	hid_end_parse(hd);
+
+	return (1);
+}
+
+/* Free config entry */
+static void
+free_hid_device(hid_device_p d)
+{
+	if (d->desc != NULL)
+		hid_dispose_report_desc(d->desc);
+
+	memset(d, 0, sizeof(*d));
+	free(d);
+}
+
+/* Re-read hids file */
+int32_t
+read_hids_file(void)
+{
+	FILE		*f;
+	hid_device_t	*d;
+	char		*line;
+	bdaddr_t	 bdaddr;
+	int32_t		 lineno;
+
+	if (hids_file == NULL) {
+		SYSLOG(LOGERR, "Unknown HIDs file name!" EOL);
+		return (-1);
+	}
+
+	if ((f = fopen(hids_file, "r")) == NULL) {
+		if (errno == ENOENT)
+			return (0);
+
+		SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL,
+			hids_file, strerror(errno), errno);
+		return (-1);
+	}
+
+	for (lineno = 1; fgets(buffer, sizeof(buffer), f) != NULL; lineno ++) {
+		if ((line = strtok(buffer, "\r\n\t ")) == NULL)
+			continue; /* ignore empty lines */
+
+		if (!bt_aton(line, &bdaddr)) {
+			SYSLOG(LOGWARNING, "Ignoring unparseable BD_ADDR in " \
+				"%s:%d" EOL, hids_file, lineno);
+			continue;
+		}
+
+		if ((d = get_hid_device(&bdaddr)) != NULL)
+			d->new_device = 0;
+	}
+
+	fclose(f);
+
+	return (0);
+}
+
+/* Write hids file */
+int32_t
+write_hids_file(void)
+{
+	char		 path[PATH_MAX];
+	FILE		*f;
+	hid_device_t	*d;
+
+	if (hids_file == NULL) {
+		SYSLOG(LOGERR, "Unknown HIDs file name!" EOL);
+		return (-1);
+	}
+
+	snprintf(path, sizeof(path), "%s.new", hids_file);
+
+	if ((f = fopen(path, "w")) == NULL) {
+		SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL,
+			path, strerror(errno), errno);
+		return (-1);
+	}
+
+	LIST_FOREACH(d, &hid_devices, next)
+		if (!d->new_device)
+			fprintf(f, "%s\n", bt_ntoa(&d->bdaddr, NULL));
+
+	fclose(f);
+
+	if (rename(path, hids_file) < 0) {
+		SYSLOG(LOGERR, "Could not rename new HIDs file '%s' to '%s'. " \
+			"%s (%d)" EOL, path, hids_file, strerror(errno), errno);
+		unlink(path);
+		return (-1);
+	}
+
+	return (0);
+}
+
diff --git a/usr.sbin/bthidd/server.c b/usr.sbin/bthidd/server.c
new file mode 100644
index 0000000000..92992eaed3
--- /dev/null
+++ b/usr.sbin/bthidd/server.c
@@ -0,0 +1,349 @@
+/*
+ * server.c
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: server.c,v 1.9 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/server.c 162494 2006-09-21 02:32:28Z emax $
+ */
+
+#include <sys/queue.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <dev/vkbd/vkbd_var.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <usbhid.h>
+#include "bthid_config.h"
+#include "bthidd.h"
+#include "kbd.h"
+
+#undef	max
+#define	max(x, y)	(((x) > (y))? (x) : (y))
+
+static int32_t	server_accept (bthid_server_p srv, int32_t fd);
+static int32_t	server_process(bthid_server_p srv, int32_t fd);
+
+/*
+ * Initialize server
+ */
+
+int32_t
+server_init(bthid_server_p srv)
+{
+	struct sockaddr_l2cap	l2addr;
+
+	assert(srv != NULL);
+
+	srv->ctrl = srv->intr = -1;
+	FD_ZERO(&srv->rfdset);
+	FD_ZERO(&srv->wfdset);
+	LIST_INIT(&srv->sessions);
+
+	/* Open /dev/consolectl */
+	srv->cons = open("/dev/consolectl", O_RDWR);
+	if (srv->cons < 0) {
+		syslog(LOG_ERR, "Could not open /dev/consolectl. %s (%d)",
+			strerror(errno), errno);
+		return (-1);
+	}
+
+	/* Create control socket */
+	srv->ctrl = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
+	if (srv->ctrl < 0) {
+		syslog(LOG_ERR, "Could not create control L2CAP socket. " \
+			"%s (%d)", strerror(errno), errno);
+		close(srv->cons);
+		return (-1);
+	}
+
+	l2addr.l2cap_len = sizeof(l2addr);
+	l2addr.l2cap_family = AF_BLUETOOTH;
+	memcpy(&l2addr.l2cap_bdaddr, &srv->bdaddr, sizeof(l2addr.l2cap_bdaddr));
+	l2addr.l2cap_psm = htole16(0x11);
+
+	if (bind(srv->ctrl, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
+		syslog(LOG_ERR, "Could not bind control L2CAP socket. " \
+			"%s (%d)", strerror(errno), errno);
+		close(srv->ctrl);
+		close(srv->cons);
+		return (-1);
+	}
+
+	if (listen(srv->ctrl, 10) < 0) {
+		syslog(LOG_ERR, "Could not listen on control L2CAP socket. " \
+			"%s (%d)", strerror(errno), errno);
+		close(srv->ctrl);
+		close(srv->cons);
+		return (-1);
+	}
+
+	/* Create intrrupt socket */
+	srv->intr = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
+	if (srv->intr < 0) {
+		syslog(LOG_ERR, "Could not create interrupt L2CAP socket. " \
+			"%s (%d)", strerror(errno), errno);
+		close(srv->ctrl);
+		close(srv->cons);
+		return (-1);
+	}
+
+	l2addr.l2cap_psm = htole16(0x13);
+
+	if (bind(srv->intr, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
+		syslog(LOG_ERR, "Could not bind interrupt L2CAP socket. " \
+			"%s (%d)", strerror(errno), errno);
+		close(srv->intr);
+		close(srv->ctrl);
+		close(srv->cons);
+		return (-1);
+	}
+
+	if (listen(srv->intr, 10) < 0) {
+		syslog(LOG_ERR, "Could not listen on interrupt L2CAP socket. "\
+			"%s (%d)", strerror(errno), errno);
+		close(srv->intr);
+		close(srv->ctrl);
+		close(srv->cons);
+		return (-1);
+	}
+
+	FD_SET(srv->ctrl, &srv->rfdset);
+	FD_SET(srv->intr, &srv->rfdset);
+	srv->maxfd = max(srv->ctrl, srv->intr);
+
+	return (0);
+}
+
+/*
+ * Shutdown server
+ */
+
+void
+server_shutdown(bthid_server_p srv)
+{
+	assert(srv != NULL);
+
+	close(srv->cons);
+	close(srv->ctrl);
+	close(srv->intr);
+
+	while (!LIST_EMPTY(&srv->sessions))
+		session_close(LIST_FIRST(&srv->sessions));
+
+	memset(srv, 0, sizeof(*srv));
+}
+
+/*
+ * Do one server iteration
+ */
+
+int32_t
+server_do(bthid_server_p srv)
+{
+	struct timeval	tv;
+	fd_set		rfdset, wfdset;
+	int32_t		n, fd;
+
+	assert(srv != NULL);
+
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+
+	/* Copy cached version of the fd sets and call select */
+	memcpy(&rfdset, &srv->rfdset, sizeof(rfdset));
+	memcpy(&wfdset, &srv->wfdset, sizeof(wfdset));
+
+	n = select(srv->maxfd + 1, &rfdset, &wfdset, NULL, &tv);
+	if (n < 0) {
+		if (errno == EINTR)  
+			return (0);
+
+		syslog(LOG_ERR, "Could not select(%d, %p, %p). %s (%d)",
+			srv->maxfd + 1, &rfdset, &wfdset, strerror(errno), errno);
+
+		return (-1);
+	}
+
+	/* Process descriptors (if any) */
+	for (fd = 0; fd < srv->maxfd + 1 && n > 0; fd ++) {
+		if (FD_ISSET(fd, &rfdset)) {
+			n --;
+
+			if (fd == srv->ctrl || fd == srv->intr)
+				server_accept(srv, fd);
+			else
+				server_process(srv, fd);
+		} else if (FD_ISSET(fd, &wfdset)) {
+			n --;
+
+			client_connect(srv, fd);
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * Accept new connection 
+ */
+
+static int32_t
+server_accept(bthid_server_p srv, int32_t fd)
+{
+	bthid_session_p		s;
+	hid_device_p		d;
+	struct sockaddr_l2cap	l2addr;
+	int32_t			new_fd;
+	socklen_t		len;
+
+	len = sizeof(l2addr);
+	if ((new_fd = accept(fd, (struct sockaddr *) &l2addr, &len)) < 0) {
+		syslog(LOG_ERR, "Could not accept %s connection. %s (%d)",
+			(fd == srv->ctrl)? "control" : "interrupt",
+			strerror(errno), errno);
+		return (-1);
+	}
+
+	/* Is device configured? */
+	if ((d = get_hid_device(&l2addr.l2cap_bdaddr)) == NULL) {
+		syslog(LOG_ERR, "Rejecting %s connection from %s. " \
+			"Device not configured",
+			(fd == srv->ctrl)? "control" : "interrupt",
+			bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
+		close(new_fd);
+		return (-1);
+	}
+
+	/* Check if we have session for the device */
+	if ((s = session_by_bdaddr(srv, &l2addr.l2cap_bdaddr)) == NULL) {
+		d->new_device = 0; /* reset new device flag */
+		write_hids_file();
+
+		/* Create new inbound session */
+		if ((s = session_open(srv, d)) == NULL) {
+			syslog(LOG_CRIT, "Could not open inbound session "
+				"for %s", bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
+			close(new_fd);
+			return (-1);
+		}
+	}
+
+	/* Update descriptors */
+	if (fd == srv->ctrl) {
+		assert(s->ctrl == -1);
+		s->ctrl = new_fd;
+		s->state = (s->intr == -1)? W4INTR : OPEN;
+	} else {
+		assert(s->intr == -1);
+		s->intr = new_fd;
+		s->state = (s->ctrl == -1)? W4CTRL : OPEN;
+	}
+
+	FD_SET(new_fd, &srv->rfdset);
+	if (new_fd > srv->maxfd)
+		srv->maxfd = new_fd;
+
+	syslog(LOG_NOTICE, "Accepted %s connection from %s",
+		(fd == srv->ctrl)? "control" : "interrupt",
+		bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
+
+	/* Register session's vkbd descriptor (if needed) for read */
+	if (s->state == OPEN && d->keyboard) {
+		assert(s->vkbd != -1);
+
+		FD_SET(s->vkbd, &srv->rfdset);
+		if (s->vkbd > srv->maxfd)
+			srv->maxfd = s->vkbd;
+	}
+
+	return (0);
+}
+
+/*
+ * Process data on the connection
+ */
+
+static int32_t
+server_process(bthid_server_p srv, int32_t fd)
+{
+	bthid_session_p		s = session_by_fd(srv, fd);
+	int32_t			len, to_read;
+	int32_t			(*cb)(bthid_session_p, uint8_t *, int32_t);
+	union {
+		uint8_t		b[1024];
+		vkbd_status_t	s;
+	}			data;
+
+	if (s == NULL)
+		return (0); /* can happen on device disconnect */
+
+
+	if (fd == s->ctrl) {
+		cb = hid_control;
+		to_read = sizeof(data.b);
+	} else if (fd == s->intr) {
+		cb = hid_interrupt;
+		to_read = sizeof(data.b);
+	} else {
+		assert(fd == s->vkbd);
+
+		cb = kbd_status_changed;
+		to_read = sizeof(data.s);
+	}
+
+	do {
+		len = read(fd, &data, to_read);
+	} while (len < 0 && errno == EINTR);
+
+	if (len < 0) {
+		syslog(LOG_ERR, "Could not read data from %s (%s). %s (%d)",
+			bt_ntoa(&s->bdaddr, NULL),
+			(fd == s->ctrl)? "control" : "interrupt",
+			strerror(errno), errno);
+		session_close(s);
+		return (0);
+	}
+
+	if (len == 0) {
+		syslog(LOG_NOTICE, "Remote device %s has closed %s connection",
+			bt_ntoa(&s->bdaddr, NULL),
+			(fd == s->ctrl)? "control" : "interrupt");
+		session_close(s);
+		return (0);
+	}
+
+	(*cb)(s, (uint8_t *) &data, len);
+
+	return (0);
+}
+
diff --git a/usr.sbin/bthidd/session.c b/usr.sbin/bthidd/session.c
new file mode 100644
index 0000000000..cb863fdaa1
--- /dev/null
+++ b/usr.sbin/bthidd/session.c
@@ -0,0 +1,184 @@
+/*
+ * session.c
+ */
+
+/*-
+ * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: session.c,v 1.3 2006/09/07 21:06:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/bthidd/session.c 162128 2006-09-07 21:47:49Z emax $
+ */
+
+#include <sys/queue.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <usbhid.h>
+#include "bthid_config.h"
+#include "bthidd.h"
+#include "kbd.h"
+
+/*
+ * Create new session
+ */
+
+bthid_session_p
+session_open(bthid_server_p srv, hid_device_p const d)
+{
+	bthid_session_p	s;
+
+	assert(srv != NULL);
+	assert(d != NULL);
+
+	if ((s = (bthid_session_p) malloc(sizeof(*s))) == NULL)
+		return (NULL);
+
+	s->srv = srv;  
+	memcpy(&s->bdaddr, &d->bdaddr, sizeof(s->bdaddr));
+	s->ctrl = -1;
+	s->intr = -1;
+
+	if (d->keyboard) {
+		/* Open /dev/vkbdctl */
+		s->vkbd = open("/dev/vkbdctl", O_RDWR);
+		if (s->vkbd < 0) {
+			syslog(LOG_ERR, "Could not open /dev/vkbdctl " \
+				"for %s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
+				strerror(errno), errno);
+			free(s);
+			return (NULL);
+		}
+	} else
+		s->vkbd = -1;
+
+	s->state = CLOSED;
+
+	s->keys1 = bit_alloc(kbd_maxkey());
+	if (s->keys1 == NULL) {
+		free(s);
+		return (NULL);
+	}
+
+	s->keys2 = bit_alloc(kbd_maxkey());
+	if (s->keys2 == NULL) {
+		free(s->keys1);
+		free(s);
+		return (NULL);
+	}
+
+	LIST_INSERT_HEAD(&srv->sessions, s, next);
+
+	return (s);
+}
+
+/*
+ * Lookup session by bdaddr
+ */
+
+bthid_session_p
+session_by_bdaddr(bthid_server_p srv, bdaddr_p bdaddr)
+{
+	bthid_session_p	s;
+
+	assert(srv != NULL);
+	assert(bdaddr != NULL);
+
+	LIST_FOREACH(s, &srv->sessions, next)
+		if (memcmp(&s->bdaddr, bdaddr, sizeof(s->bdaddr)) == 0)
+			break;
+
+	return (s);
+}
+
+/*
+ * Lookup session by fd
+ */
+
+bthid_session_p
+session_by_fd(bthid_server_p srv, int32_t fd)
+{
+	bthid_session_p	s;
+
+	assert(srv != NULL);
+	assert(fd >= 0);
+
+	LIST_FOREACH(s, &srv->sessions, next)
+		if (s->ctrl == fd || s->intr == fd || s->vkbd == fd)
+			break;
+
+	return (s);
+}
+
+/*
+ * Close session
+ */
+
+void
+session_close(bthid_session_p s)
+{
+	assert(s != NULL);
+	assert(s->srv != NULL);
+
+	LIST_REMOVE(s, next);
+
+	if (s->intr != -1) {
+		FD_CLR(s->intr, &s->srv->rfdset);
+		FD_CLR(s->intr, &s->srv->wfdset);
+		close(s->intr);
+
+		if (s->srv->maxfd == s->intr)
+			s->srv->maxfd --;
+	}
+
+	if (s->ctrl != -1) {
+		FD_CLR(s->ctrl, &s->srv->rfdset);
+		FD_CLR(s->ctrl, &s->srv->wfdset);
+		close(s->ctrl);
+
+		if (s->srv->maxfd == s->ctrl)
+			s->srv->maxfd --;
+	}
+
+	if (s->vkbd != -1) {
+		FD_CLR(s->vkbd, &s->srv->rfdset);
+		close(s->vkbd);
+
+		if (s->srv->maxfd == s->vkbd)
+			s->srv->maxfd --;
+	}
+
+	free(s->keys1);
+	free(s->keys2);
+
+	memset(s, 0, sizeof(*s));
+	free(s);
+}
+
diff --git a/usr.sbin/btpand/Makefile b/usr.sbin/btpand/Makefile
new file mode 100644
index 0000000000..6dacea4278
--- /dev/null
+++ b/usr.sbin/btpand/Makefile
@@ -0,0 +1,13 @@
+# $NetBSD: Makefile,v 1.2 2008/08/18 08:25:32 plunky Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/btpand/Makefile 187938 2009-01-30 22:23:21Z emax $
+
+PROG=	btpand
+MAN=	btpand.8
+SRCS=	btpand.c bnep.c channel.c client.c event.c packet.c server.c sdp.c tap.c
+
+WARNS?=	3
+
+DPADD+=	${LIBBLUETOOTH} ${LIBSDP} ${LIBUTIL}
+LDADD+=	-lbluetooth -lsdp -lutil
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/btpand/bnep.c b/usr.sbin/btpand/bnep.c
new file mode 100644
index 0000000000..e6df522500
--- /dev/null
+++ b/usr.sbin/btpand/bnep.c
@@ -0,0 +1,755 @@
+/*	$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/bnep.c 187938 2009-01-30 22:23:21Z emax $ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
+
+#include <sys/uio.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "btpand.h"
+#include "bnep.h"
+
+static bool bnep_recv_extension(packet_t *);
+static size_t bnep_recv_control(channel_t *, uint8_t *, size_t, bool);
+static size_t bnep_recv_control_command_not_understood(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_setup_connection_req(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_setup_connection_rsp(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_filter_net_type_set(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_filter_net_type_rsp(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_filter_multi_addr_set(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_filter_multi_addr_rsp(channel_t *, uint8_t *, size_t);
+
+static bool bnep_pfilter(channel_t *, packet_t *);
+static bool bnep_mfilter(channel_t *, packet_t *);
+
+static uint8_t NAP_UUID[] = {
+	0x00, 0x00, 0x11, 0x16,
+	0x00, 0x00,
+	0x10, 0x00,
+	0x80, 0x00,
+	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+};
+
+static uint8_t GN_UUID[] = {
+	0x00, 0x00, 0x11, 0x17,
+	0x00, 0x00,
+	0x10, 0x00,
+	0x80, 0x00,
+	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+};
+
+static uint8_t PANU_UUID[] = {
+	0x00, 0x00, 0x11, 0x15,
+	0x00, 0x00,
+	0x10, 0x00,
+	0x80, 0x00,
+	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+};
+
+/*
+ * receive BNEP packet
+ * return true if packet is to be forwarded
+ */
+bool
+bnep_recv(packet_t *pkt)
+{
+	size_t len;
+	uint8_t type;
+
+	if (pkt->len < 1)
+		return false;
+
+	type = pkt->ptr[0];
+	packet_adj(pkt, 1);
+
+	switch (BNEP_TYPE(type)) {
+	case BNEP_GENERAL_ETHERNET:
+		if (pkt->len < (ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) {
+			log_debug("dropped short packet (type 0x%2.2x)", type);
+			return false;
+		}
+
+		pkt->dst = pkt->ptr;
+		packet_adj(pkt, ETHER_ADDR_LEN);
+		pkt->src = pkt->ptr;
+		packet_adj(pkt, ETHER_ADDR_LEN);
+		pkt->type = pkt->ptr;
+		packet_adj(pkt, ETHER_TYPE_LEN);
+		break;
+
+	case BNEP_CONTROL:
+		len = bnep_recv_control(pkt->chan, pkt->ptr, pkt->len, false);
+		if (len == 0)
+			return false;
+
+		packet_adj(pkt, len);
+		break;
+
+	case BNEP_COMPRESSED_ETHERNET:
+		if (pkt->len < ETHER_TYPE_LEN) {
+			log_debug("dropped short packet (type 0x%2.2x)", type);
+			return false;
+		}
+
+		pkt->dst = pkt->chan->laddr;
+		pkt->src = pkt->chan->raddr;
+		pkt->type = pkt->ptr;
+		packet_adj(pkt, ETHER_TYPE_LEN);
+		break;
+
+	case BNEP_COMPRESSED_ETHERNET_SRC_ONLY:
+		if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
+			log_debug("dropped short packet (type 0x%2.2x)", type);
+			return false;
+		}
+
+		pkt->dst = pkt->chan->laddr;
+		pkt->src = pkt->ptr;
+		packet_adj(pkt, ETHER_ADDR_LEN);
+		pkt->type = pkt->ptr;
+		packet_adj(pkt, ETHER_TYPE_LEN);
+		break;
+
+	case BNEP_COMPRESSED_ETHERNET_DST_ONLY:
+		if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
+			log_debug("dropped short packet (type 0x%2.2x)", type);
+			return false;
+		}
+
+		pkt->dst = pkt->ptr;
+		packet_adj(pkt, ETHER_ADDR_LEN);
+		pkt->src = pkt->chan->raddr;
+		pkt->type = pkt->ptr;
+		packet_adj(pkt, ETHER_TYPE_LEN);
+		break;
+
+	default:
+		/*
+		 * Any packet containing a reserved BNEP
+		 * header packet type SHALL be dropped.
+		 */
+
+		log_debug("dropped packet with reserved type 0x%2.2x", type);
+		return false;
+	}
+
+	if (BNEP_TYPE_EXT(type)
+	    && !bnep_recv_extension(pkt))
+		return false;	/* invalid extensions */
+
+	if (BNEP_TYPE(type) == BNEP_CONTROL
+	    || pkt->chan->state != CHANNEL_OPEN)
+		return false;	/* no forwarding */
+
+	return true;
+}
+
+static bool
+bnep_recv_extension(packet_t *pkt)
+{
+	exthdr_t *eh;
+	size_t len, size;
+	uint8_t type;
+
+	do {
+		if (pkt->len < 2)
+			return false;
+
+		type = pkt->ptr[0];
+		size = pkt->ptr[1];
+
+		if (pkt->len < size + 2)
+			return false;
+
+		switch (type) {
+		case BNEP_EXTENSION_CONTROL:
+			len = bnep_recv_control(pkt->chan, pkt->ptr + 2, size, true);
+			if (len != size)
+				log_err("ignored spurious data in exthdr");
+
+			break;
+
+		default:
+			/* Unknown extension headers in data packets	 */
+			/* SHALL be forwarded irrespective of any	 */
+			/* network protocol or multicast filter settings */
+			/* and any local filtering policy.		 */
+
+			eh = malloc(sizeof(exthdr_t));
+			if (eh == NULL) {
+				log_err("exthdr malloc() failed: %m");
+				break;
+			}
+
+			eh->ptr = pkt->ptr;
+			eh->len = size;
+			STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
+			break;
+		}
+
+		packet_adj(pkt, size + 2);
+	} while (BNEP_TYPE_EXT(type));
+
+	return true;
+}
+
+static size_t
+bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
+{
+	uint8_t type;
+	size_t len;
+
+	if (size-- < 1)
+		return 0;
+
+	type = *ptr++;
+
+	switch (type) {
+	case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
+		len = bnep_recv_control_command_not_understood(chan, ptr, size);
+		break;
+
+	case BNEP_SETUP_CONNECTION_REQUEST:
+		if (isext)
+			return 0;	/* not allowed in extension headers */
+
+		len = bnep_recv_setup_connection_req(chan, ptr, size);
+		break;
+
+	case BNEP_SETUP_CONNECTION_RESPONSE:
+		if (isext)
+			return 0;	/* not allowed in extension headers */
+
+		len = bnep_recv_setup_connection_rsp(chan, ptr, size);
+		break;
+
+	case BNEP_FILTER_NET_TYPE_SET:
+		len = bnep_recv_filter_net_type_set(chan, ptr, size);
+		break;
+
+	case BNEP_FILTER_NET_TYPE_RESPONSE:
+		len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
+		break;
+
+	case BNEP_FILTER_MULTI_ADDR_SET:
+		len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
+		break;
+
+	case BNEP_FILTER_MULTI_ADDR_RESPONSE:
+		len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
+		break;
+
+	default:
+		len = 0;
+		break;
+	}
+
+	if (len == 0)
+		bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
+
+	return len;
+}
+
+static size_t
+bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	uint8_t type;
+
+	if (size < 1)
+		return 0;
+
+	type = *ptr++;
+	log_err("received Control Command Not Understood (0x%2.2x)", type);
+
+	/* we didn't send any reserved commands, just cut them off */
+	channel_close(chan);
+
+	return 1;
+}
+
+static size_t
+bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	uint8_t off;
+	int src, dst, rsp;
+	size_t len;
+
+	if (size < 1)
+		return 0;
+
+	len = *ptr++;
+	if (size < (len * 2 + 1))
+		return 0;
+
+	if (chan->state != CHANNEL_WAIT_CONNECT_REQ
+	    && chan->state != CHANNEL_OPEN) {
+		log_debug("ignored");
+		return (len * 2 + 1);
+	}
+
+	if (len == 2)
+		off = 2;
+	else if (len == 4)
+		off = 0;
+	else if (len == 16)
+		off = 0;
+	else {
+		rsp = BNEP_SETUP_INVALID_UUID_SIZE;
+		goto done;
+	}
+
+	if (memcmp(ptr, NAP_UUID + off, len) == 0)
+		dst = SDP_SERVICE_CLASS_NAP;
+	else if (memcmp(ptr, GN_UUID + off, len) == 0)
+		dst = SDP_SERVICE_CLASS_GN;
+	else if (memcmp(ptr, PANU_UUID + off, len) == 0)
+		dst = SDP_SERVICE_CLASS_PANU;
+	else
+		dst = 0;
+
+	if (dst != service_class) {
+		rsp = BNEP_SETUP_INVALID_DST_UUID;
+		goto done;
+	}
+
+	ptr += len;
+
+	if (memcmp(ptr, NAP_UUID + off, len) == 0)
+		src = SDP_SERVICE_CLASS_NAP;
+	else if (memcmp(ptr, GN_UUID + off, len) == 0)
+		src = SDP_SERVICE_CLASS_GN;
+	else if (memcmp(ptr, PANU_UUID + off, len) == 0)
+		src = SDP_SERVICE_CLASS_PANU;
+	else
+		src = 0;
+
+	if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU)
+	    || src == 0) {
+		rsp = BNEP_SETUP_INVALID_SRC_UUID;
+		goto done;
+	}
+
+	rsp = BNEP_SETUP_SUCCESS;
+	chan->state = CHANNEL_OPEN;
+	channel_timeout(chan, 0);
+
+done:
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp);
+	return (len * 2 + 1);
+}
+
+static size_t
+bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	int rsp;
+
+	if (size < 2)
+		return 0;
+
+	rsp = be16dec(ptr);
+
+	if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
+		log_debug("ignored");
+		return 2;
+	}
+
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	if (rsp == BNEP_SETUP_SUCCESS) {
+		chan->state = CHANNEL_OPEN;
+		channel_timeout(chan, 0);
+	} else {
+		channel_close(chan);
+	}
+
+	return 2;
+}
+
+static size_t
+bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	pfilter_t *pf;
+	int i, nf, rsp;
+	size_t len;
+
+	if (size < 2)
+		return 0;
+
+	len = be16dec(ptr);
+	ptr += 2;
+
+	if (size < (len + 2))
+		return 0;
+
+	if (chan->state != CHANNEL_OPEN) {
+		log_debug("ignored");
+		return (len + 2);
+	}
+
+	nf = len / 4;
+	pf = malloc(nf * sizeof(pfilter_t));
+	if (pf == NULL) {
+		rsp = BNEP_FILTER_TOO_MANY_FILTERS;
+		goto done;
+	}
+
+	log_debug("nf = %d", nf);
+
+	for (i = 0; i < nf; i++) {
+		pf[i].start = be16dec(ptr);
+		ptr += 2;
+		pf[i].end = be16dec(ptr);
+		ptr += 2;
+
+		if (pf[i].start > pf[i].end) {
+			free(pf);
+			rsp = BNEP_FILTER_INVALID_RANGE;
+			goto done;
+		}
+
+		log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
+	}
+
+	if (chan->pfilter)
+		free(chan->pfilter);
+
+	chan->pfilter = pf;
+	chan->npfilter = nf;
+
+	rsp = BNEP_FILTER_SUCCESS;
+
+done:
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
+	return (len + 2);
+}
+
+static size_t
+bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	int rsp;
+
+	if (size < 2)
+		return 0;
+
+	if (chan->state != CHANNEL_OPEN) {
+		log_debug("ignored");
+		return 2;
+	}
+
+	rsp = be16dec(ptr);
+
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	/* we did not send any filter_net_type_set message */
+	return 2;
+}
+
+static size_t
+bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	mfilter_t *mf;
+	int i, nf, rsp;
+	size_t len;
+
+	if (size < 2)
+		return 0;
+
+	len = be16dec(ptr);
+	ptr += 2;
+
+	if (size < (len + 2))
+		return 0;
+
+	if (chan->state != CHANNEL_OPEN) {
+		log_debug("ignored");
+		return (len + 2);
+	}
+
+	nf = len / (ETHER_ADDR_LEN * 2);
+	mf = malloc(nf * sizeof(mfilter_t));
+	if (mf == NULL) {
+		rsp = BNEP_FILTER_TOO_MANY_FILTERS;
+		goto done;
+	}
+
+	log_debug("nf = %d", nf);
+
+	for (i = 0; i < nf; i++) {
+		memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
+		ptr += ETHER_ADDR_LEN;
+
+		memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
+		ptr += ETHER_ADDR_LEN;
+
+		if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) {
+			free(mf);
+			rsp = BNEP_FILTER_INVALID_RANGE;
+			goto done;
+		}
+
+		log_debug("pf[%d] = "
+		    "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+		    "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i,
+		    mf[i].start[0], mf[i].start[1], mf[i].start[2],
+		    mf[i].start[3], mf[i].start[4], mf[i].start[5],
+		    mf[i].end[0], mf[i].end[1], mf[i].end[2],
+		    mf[i].end[3], mf[i].end[4], mf[i].end[5]);
+	}
+
+	if (chan->mfilter)
+		free(chan->mfilter);
+
+	chan->mfilter = mf;
+	chan->nmfilter = nf;
+
+	rsp = BNEP_FILTER_SUCCESS;
+
+done:
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
+	return (len + 2);
+}
+
+static size_t
+bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	int rsp;
+
+	if (size < 2)
+		return false;
+
+	if (chan->state != CHANNEL_OPEN) {
+		log_debug("ignored");
+		return 2;
+	}
+
+	rsp = be16dec(ptr);
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	/* we did not send any filter_multi_addr_set message */
+	return 2;
+}
+
+void
+bnep_send_control(channel_t *chan, uint8_t type, ...)
+{
+	packet_t *pkt;
+	uint8_t *p;
+	va_list ap;
+
+	assert(chan->state != CHANNEL_CLOSED);
+
+	pkt = packet_alloc(chan);
+	if (pkt == NULL)
+		return;
+
+	p = pkt->ptr;
+	va_start(ap, type);
+
+	*p++ = BNEP_CONTROL;
+	*p++ = type;
+
+	switch(type) {
+	case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
+		*p++ = va_arg(ap, int);
+		break;
+
+	case BNEP_SETUP_CONNECTION_REQUEST:
+		*p++ = va_arg(ap, int);
+		be16enc(p, va_arg(ap, int));
+		p += 2;
+		be16enc(p, va_arg(ap, int));
+		p += 2;
+		break;
+
+	case BNEP_SETUP_CONNECTION_RESPONSE:
+	case BNEP_FILTER_NET_TYPE_RESPONSE:
+	case BNEP_FILTER_MULTI_ADDR_RESPONSE:
+		be16enc(p, va_arg(ap, int));
+		p += 2;
+		break;
+
+	case BNEP_FILTER_NET_TYPE_SET:		/* TODO */
+	case BNEP_FILTER_MULTI_ADDR_SET:	/* TODO */
+	default:
+		log_err("Can't send control type 0x%2.2x", type);
+		break;
+	}
+
+	va_end(ap);
+	pkt->len = p - pkt->ptr;
+
+	channel_put(chan, pkt);
+	packet_free(pkt);
+}
+
+/*
+ * BNEP send packet routine
+ * return true if packet can be removed from queue
+ */
+bool
+bnep_send(channel_t *chan, packet_t *pkt)
+{
+	struct iovec iov[2];
+	uint8_t *p, *type, *proto;
+	exthdr_t *eh;
+	bool src, dst;
+	size_t nw;
+
+	if (pkt->type == NULL) {
+		iov[0].iov_base = pkt->ptr;
+		iov[0].iov_len = pkt->len;
+		iov[1].iov_base = NULL;
+		iov[1].iov_len = 0;
+	} else {
+		p = chan->sendbuf;
+
+		dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
+		src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
+
+		type = p;
+		p += 1;
+
+		if (dst && src)
+			*type = BNEP_GENERAL_ETHERNET;
+		else if (dst && !src)
+			*type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
+		else if (!dst && src)
+			*type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
+		else /* (!dst && !src) */
+			*type = BNEP_COMPRESSED_ETHERNET;
+
+		if (dst) {
+			memcpy(p, pkt->dst, ETHER_ADDR_LEN);
+			p += ETHER_ADDR_LEN;
+		}
+
+		if (src) {
+			memcpy(p, pkt->src, ETHER_ADDR_LEN);
+			p += ETHER_ADDR_LEN;
+		}
+
+		proto = p;
+		memcpy(p, pkt->type, ETHER_TYPE_LEN);
+		p += ETHER_TYPE_LEN;
+
+		STAILQ_FOREACH(eh, &pkt->extlist, next) {
+			if (p + eh->len > chan->sendbuf + chan->mtu)
+				break;
+
+			*type |= BNEP_EXT;
+			type = p;
+
+			memcpy(p, eh->ptr, eh->len);
+			p += eh->len;
+		}
+
+		*type &= ~BNEP_EXT;
+
+		iov[0].iov_base = chan->sendbuf;
+		iov[0].iov_len = (p - chan->sendbuf);
+
+		if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
+		    && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
+			iov[1].iov_base = pkt->ptr;
+			iov[1].iov_len = pkt->len;
+		} else if (be16dec(proto) == ETHERTYPE_VLAN
+		    && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
+			iov[1].iov_base = pkt->ptr;
+			iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
+		} else {
+			iov[1].iov_base = NULL;
+			iov[1].iov_len = 0;
+			memset(proto, 0, ETHER_TYPE_LEN);
+		}
+	}
+
+	if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
+		log_err("packet exceeded MTU (dropped)");
+		return false;
+	}
+
+	nw = writev(chan->fd, iov, __arraycount(iov));
+	return (nw > 0);
+}
+
+static bool
+bnep_pfilter(channel_t *chan, packet_t *pkt)
+{
+	int proto, i;
+
+	proto = be16dec(pkt->type);
+	if (proto == ETHERTYPE_VLAN) {	/* IEEE 802.1Q tag header */
+		if (pkt->len < 4)
+			return false;
+
+		proto = be16dec(pkt->ptr + 2);
+	}
+
+	for (i = 0; i < chan->npfilter; i++) {
+		if (chan->pfilter[i].start <= proto
+		    && chan->pfilter[i].end >=proto)
+			return true;
+	}
+
+	return false;
+}
+
+static bool
+bnep_mfilter(channel_t *chan, packet_t *pkt)
+{
+	int i;
+
+	if (!ETHER_IS_MULTICAST(pkt->dst))
+		return true;
+
+	for (i = 0; i < chan->nmfilter; i++) {
+		if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
+		    && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)
+			return true;
+	}
+
+	return false;
+}
diff --git a/usr.sbin/btpand/bnep.h b/usr.sbin/btpand/bnep.h
new file mode 100644
index 0000000000..7ac2fa6346
--- /dev/null
+++ b/usr.sbin/btpand/bnep.h
@@ -0,0 +1,72 @@
+/*	$NetBSD: bnep.h,v 1.1 2008/08/17 13:20:57 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/bnep.h 187938 2009-01-30 22:23:21Z emax $ */
+
+/*
+ * Constants defined in the Bluetooth Network Encapsulation
+ * Protocol (BNEP) specification v1.0
+ */
+
+#define	BNEP_MTU_MIN		1691
+
+#define BNEP_EXT		0x80
+#define	BNEP_TYPE(x)		((x) & 0x7f)
+#define BNEP_TYPE_EXT(x)	(((x) & BNEP_EXT) == BNEP_EXT)
+
+/* BNEP packet types */
+#define	BNEP_GENERAL_ETHERNET			0x00
+#define	BNEP_CONTROL				0x01
+#define	BNEP_COMPRESSED_ETHERNET		0x02
+#define	BNEP_COMPRESSED_ETHERNET_SRC_ONLY	0x03
+#define	BNEP_COMPRESSED_ETHERNET_DST_ONLY	0x04
+
+/* BNEP extension header types */
+#define	BNEP_EXTENSION_CONTROL			0x00
+
+/* BNEP control types */
+#define	BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD	0x00
+#define	BNEP_SETUP_CONNECTION_REQUEST		0x01
+#define	BNEP_SETUP_CONNECTION_RESPONSE		0x02
+#define	BNEP_FILTER_NET_TYPE_SET		0x03
+#define	BNEP_FILTER_NET_TYPE_RESPONSE		0x04
+#define	BNEP_FILTER_MULTI_ADDR_SET		0x05
+#define	BNEP_FILTER_MULTI_ADDR_RESPONSE		0x06
+
+/* BNEP setup response codes */
+#define	BNEP_SETUP_SUCCESS		0x0000
+#define	BNEP_SETUP_INVALID_SRC_UUID	0x0001
+#define	BNEP_SETUP_INVALID_DST_UUID	0x0002
+#define	BNEP_SETUP_INVALID_UUID_SIZE	0x0003
+#define	BNEP_SETUP_NOT_ALLOWED		0x0004
+
+/* BNEP filter return codes */
+#define	BNEP_FILTER_SUCCESS		0x0000
+#define	BNEP_FILTER_UNSUPPORTED_REQUEST	0x0001
+#define	BNEP_FILTER_INVALID_RANGE	0x0002
+#define	BNEP_FILTER_TOO_MANY_FILTERS	0x0003
+#define	BNEP_FILTER_SECURITY_FAILURE	0x0004
diff --git a/usr.sbin/btpand/btpand.8 b/usr.sbin/btpand/btpand.8
new file mode 100644
index 0000000000..603b474b36
--- /dev/null
+++ b/usr.sbin/btpand/btpand.8
@@ -0,0 +1,240 @@
+.\" $NetBSD: btpand.8,v 1.3 2008/08/17 14:43:07 plunky Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/btpand/btpand.8 261634 2014-02-08 13:37:02Z joel $
+.\"
+.\" Copyright (c) 2008 Iain Hibbert
+.\" 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 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.
+.\"
+.Dd August 17, 2008
+.Dt BTPAND 8
+.Os
+.Sh NAME
+.Nm btpand
+.Nd Bluetooth PAN daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl i Ar ifname
+.Op Fl m Ar mode
+.Fl a Ar addr
+.Fl d Ar device
+.Brq Fl s Ar service | Fl S Ar service Op Fl p Ar psm
+.Nm
+.Op Fl c Ar path
+.Op Fl i Ar ifname
+.Op Fl l Ar limit
+.Op Fl m Ar mode
+.Op Fl p Ar psm
+.Fl d Ar device
+.Brq Fl s Ar service | Fl S Ar service
+.Sh DESCRIPTION
+The
+.Nm
+daemon handles Bluetooth Personal Area Networking services
+in the system.
+It can operate in client mode as a Personal Area Networking User
+.Pq PANU
+or in server mode as Network Access Point
+.Pq NAP ,
+Group ad-hoc Network
+.Pq GN
+or PANU host.
+.Nm
+connects to the system via a
+.Xr tap 4
+virtual Ethernet device and forwards Ethernet packets to
+remote Bluetooth devices using the Bluetooth Network Encapsulation
+Protocol
+.Pq BNEP .
+.Pp
+The PANU client is the device that uses either the NAP or GN
+service, or can talk directly to a PANU host in a crossover
+cable fashion.
+.Pp
+A GN host forwards Ethernet packets to each of the connected PAN
+users as needed but does not provide access to any additional networks.
+.Pp
+The NAP service provides some of the features of an Ethernet bridge,
+with the NAP host forwarding Ethernet packets between each of the
+connected PAN users, and a different network
+media.
+.Pp
+Note, the only differences between NAP and GN services as implemented by
+.Nm
+are in the SDP service record.
+The bridging of packets by the NAP must be configured separately.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl a Ar address"
+.It Fl a Ar address
+In client mode, address of remote server.
+May be given as BDADDR or name, in which case
+.Nm
+will attempt to resolve the address via the
+.Xr bt_gethostbyname 3
+call.
+.It Fl c Ar path
+In server mode, specify
+.Ar path
+to the
+.Xr sdpd 8
+control socket.
+The default path is
+.Pa /var/run/sdp .
+.It Fl d Ar device
+Restrict connections to the local
+.Ar device .
+May be given as BDADDR or name, in which case
+.Nm
+will attempt to resolve the address via the
+.Xr bt_devaddr 3
+call.
+.Nm
+will set the
+.Xr tap 4
+interface physical address to the BDADDR
+of the Bluetooth radio.
+.It Fl i Ar ifname
+.Nm
+uses the
+.Xr tap 4
+driver to create a new network interface for use.
+Use this option to select a specific
+.Xr tap 4
+device interface which must already be created.
+.It Fl l Ar limit
+In server mode, limit the number of simultaneous connections.
+The default limit is 7 for NAP and GN servers,
+and 1 for a PANU server.
+.It Fl m Ar mode
+Set L2CAP connection link mode.
+Supported modes are:
+.Pp
+.Bl -tag -width 8n -compact
+.It auth
+require devices to be paired.
+.It encrypt
+auth, plus enable encryption.
+.It secure
+encryption, plus change of link key.
+.El
+.Pp
+NOT YET SUPPORTED.
+Use global device settings to set authentication and encryption.
+.It Fl p Ar psm
+Use an alternative L2CAP Protocol/Service Multiplexer
+.Pq PSM
+for server mode or client mode
+.Pq when not using Service Discovery .
+The default PSM for BNEP is 15
+.Pq 0x000f .
+.It Fl s Ar service
+Name of
+.Ar service
+to provide or connect to, the following services are recognised:
+.Pp
+.Bl -tag -width 8n -compact
+.It GN
+Group ad-hoc Network.
+.It NAP
+Network Access Point.
+.It PANU
+Personal Area Networking User.
+.El
+.It Fl S Ar service
+As per
+.Fl s
+except that
+.Nm
+will not use SDP services for connection setup.
+.El
+.Pp
+When providing networking services, the Bluetooth PAN profile says that the
+.Sq Class of Device
+property of the bluetooth controller SHALL include Networking capability
+.Pq set bit 0x020000 .
+See
+.Xr hccontrol 8
+for details.
+.Pp
+After
+.Nm
+has set up the client or server connection and opened the
+.Xr tap 4
+interface, it will create a pid file and detach.
+.Sh FILES
+.Bl -tag -width "Pa /etc/bluetooth/hosts" -compact
+.It Pa /dev/tap
+.It Pa /etc/bluetooth/hosts
+.It Pa /var/run/sdp
+.It Pa /var/run/tap Ns Em N Ns No .pid
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+.Dl ifconfig tap1 create
+.Dl btpand -a host -d mydevice -s NAP -i tap1
+.Dl dhclient tap1
+.Pp
+Will create a connection to the NAP on
+.Ar host ,
+and link that to the
+.Ar tap1
+interface.
+.Pp
+.Dl btpand -d mydevice -s GN
+.Pp
+Will create a Group Network and register the GN service with the local
+SDP server.
+.Sh SEE ALSO
+.Xr bluetooth 3 ,
+.Xr tap 4 ,
+.Xr bridge 4 ,
+.Xr hccontrol 8 ,
+.Xr dhclient 8 ,
+.Xr ifconfig 8 ,
+.Xr sdpd 8
+.Pp
+The
+.Qq Personal Area Networking Profile
+and
+.Qq Bluetooth Network Encapsulation Protocol
+specifications are available at
+.Dl http://www.bluetooth.com/
+.Sh AUTHORS
+.An Iain Hibbert
+.Sh BUGS
+There is no way to supply alternative values for the SDP record.
+.Pp
+There is no way to set net type or multicast address filters.
+.Pp
+.Nm
+does not do any address routing except to directly connected
+unicast addresses.
+All other packets are multicast.
+.Pp
+As
+.Nm
+uses the BDADDR of the Bluetooth radio as the physical address
+of the tap, only one instance can be run per radio.
+.Pp
+.Nm
+can only provide a single service.
diff --git a/usr.sbin/btpand/btpand.c b/usr.sbin/btpand/btpand.c
new file mode 100644
index 0000000000..e572dbac43
--- /dev/null
+++ b/usr.sbin/btpand/btpand.c
@@ -0,0 +1,293 @@
+/*	$NetBSD: btpand.c,v 1.1 2008/08/17 13:20:57 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/btpand.c 192308 2009-05-18 16:00:18Z emax $ */
+
+#include <sys/cdefs.h>
+__COPYRIGHT("@(#) Copyright (c) 2008 Iain Hibbert. All rights reserved.");
+__RCSID("$NetBSD: btpand.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
+
+#include <sys/wait.h>
+
+#include <bluetooth.h>
+#include <err.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "btpand.h"
+
+/* global variables */
+const char *	control_path;		/* -c <path> */
+const char *	interface_name;		/* -i <ifname> */
+const char *	service_name;		/* -s <service> */
+uint16_t	service_class;
+
+bdaddr_t	local_bdaddr;		/* -d <addr> */
+bdaddr_t	remote_bdaddr;		/* -a <addr> */
+uint16_t	l2cap_psm;		/* -p <psm> */
+int		l2cap_mode;		/* -m <mode> */
+
+int		server_limit;		/* -n <limit> */
+
+static const struct {
+	const char *	name;
+	uint16_t	class;
+	const char *	desc;
+} services[] = {
+	{ "PANU", SDP_SERVICE_CLASS_PANU, "Personal Area Networking User" },
+	{ "NAP",  SDP_SERVICE_CLASS_NAP,  "Network Acess Point"		  },
+	{ "GN",	  SDP_SERVICE_CLASS_GN,   "Group Network"		  },
+};
+
+static void main_exit(int);
+static void main_detach(void);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+	unsigned long	ul;
+	char *		ep;
+	int		ch, status;
+
+	while ((ch = getopt(argc, argv, "a:c:d:i:l:m:p:S:s:")) != -1) {
+		switch (ch) {
+		case 'a': /* remote address */
+			if (!bt_aton(optarg, &remote_bdaddr)) {
+				struct hostent  *he;
+
+				if ((he = bt_gethostbyname(optarg)) == NULL)
+					errx(EXIT_FAILURE, "%s: %s",
+					    optarg, hstrerror(h_errno));
+
+				bdaddr_copy(&remote_bdaddr,
+					(bdaddr_t *)he->h_addr);
+			}
+
+			break;
+
+		case 'c': /* control socket path */
+			control_path = optarg;
+			break;
+
+		case 'd': /* local address */
+			if (!bt_devaddr(optarg, &local_bdaddr)) {
+				struct hostent  *he;
+
+				if ((he = bt_gethostbyname(optarg)) == NULL)
+					errx(EXIT_FAILURE, "%s: %s",
+					    optarg, hstrerror(h_errno));
+
+				bdaddr_copy(&local_bdaddr,
+					(bdaddr_t *)he->h_addr);
+			}
+			break;
+
+		case 'i': /* tap interface name */
+			if (strchr(optarg, '/') == NULL) {
+				asprintf(&ep, "/dev/%s", optarg);
+				interface_name = ep;
+			} else
+				interface_name = optarg;
+			break;
+
+		case 'l': /* limit server sessions */
+			ul = strtoul(optarg, &ep, 10);
+			if (*optarg == '\0' || *ep != '\0' || ul == 0)
+				errx(EXIT_FAILURE, "%s: invalid session limit",
+					optarg);
+
+			server_limit = ul;
+			break;
+
+		case 'm': /* link mode */
+			warnx("Setting link mode is not yet supported");
+			break;
+
+		case 'p': /* protocol/service multiplexer */
+			ul = strtoul(optarg, &ep, 0);
+			if (*optarg == '\0' || *ep != '\0'
+			    || ul > 0xffff || L2CAP_PSM_INVALID(ul))
+				errx(EXIT_FAILURE, "%s: invalid PSM", optarg);
+
+			l2cap_psm = ul;
+			break;
+
+		case 's': /* service */
+		case 'S': /* service (no SDP) */
+			for (ul = 0; strcasecmp(optarg, services[ul].name); ul++) {
+				if (ul == __arraycount(services))
+					errx(EXIT_FAILURE, "%s: unknown service", optarg);
+			}
+
+			if (ch == 's')
+				service_name = services[ul].name;
+
+			service_class = services[ul].class;
+			break;
+
+		default:
+			usage();
+			/* NOTREACHED */
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	/* validate options */
+	if (bdaddr_any(&local_bdaddr) || service_class == 0)
+		usage();
+
+	if (!bdaddr_any(&remote_bdaddr) && (server_limit != 0 ||
+	    control_path != 0 || (service_name != NULL && l2cap_psm != 0)))
+		usage();
+
+	/* default options */
+	if (interface_name == NULL)
+		interface_name = "/dev/tap";
+
+	if (l2cap_psm == 0)
+		l2cap_psm = L2CAP_PSM_BNEP;
+
+	if (bdaddr_any(&remote_bdaddr) && server_limit == 0) {
+		if (service_class == SDP_SERVICE_CLASS_PANU)
+			server_limit = 1;
+		else
+			server_limit = 7;
+	}
+
+#ifdef L2CAP_LM_MASTER
+	if (server_limit > 1 && service_class != SDP_SERVICE_CLASS_PANU)
+		l2cap_mode |= L2CAP_LM_MASTER;
+#endif
+
+	/*
+	 * fork() now so that the setup can be done in the child process
+	 * (as kqueue is not inherited) but block in the parent until the
+	 * setup is finished so we can return an error if necessary.
+	 */
+	switch(fork()) {
+	case -1: /* bad */
+		err(EXIT_FAILURE, "fork() failed");
+
+	case 0:	/* child */
+		signal(SIGPIPE, SIG_IGN);
+
+		openlog(getprogname(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON);
+
+		channel_init();
+		server_init();
+		event_init();
+		client_init();
+		tap_init();
+
+		main_detach();
+
+		event_dispatch();
+		break;
+
+	default: /* parent */
+		signal(SIGUSR1, main_exit);
+		wait(&status);
+
+		if (WIFEXITED(status))
+			exit(WEXITSTATUS(status));
+
+		break;
+	}
+
+	err(EXIT_FAILURE, "exiting");
+}
+
+static void
+main_exit(int s)
+{
+
+	/* child is all grown up */
+	_exit(EXIT_SUCCESS);
+}
+
+static void
+main_detach(void)
+{
+	int fd;
+
+	if (kill(getppid(), SIGUSR1) == -1)
+		log_err("Could not signal main process: %m");
+
+	if (setsid() == -1)
+		log_err("setsid() failed");
+
+	fd = open(_PATH_DEVNULL, O_RDWR, 0);
+	if (fd == -1) {
+		log_err("Could not open %s", _PATH_DEVNULL);
+	} else {
+		(void)dup2(fd, STDIN_FILENO);
+		(void)dup2(fd, STDOUT_FILENO);
+		(void)dup2(fd, STDERR_FILENO);
+		close(fd);
+	}
+}
+
+static void
+usage(void)
+{
+	const char *p = getprogname();
+	int n = strlen(p);
+
+	fprintf(stderr,
+	    "usage: %s [-i ifname] [-m mode] -a address -d device\n"
+	    "       %*s {-s service | -S service [-p psm]}\n"
+	    "       %s [-c path] [-i ifname] [-l limit] [-m mode] [-p psm] -d device\n"
+	    "       %*s {-s service | -S service}\n"
+	    "\n"
+	    "Where:\n"
+	    "\t-a address  remote bluetooth device\n"
+	    "\t-c path     SDP server socket\n"
+	    "\t-d device   local bluetooth device\n"
+	    "\t-i ifname   tap interface\n"
+	    "\t-l limit    limit server sessions\n"
+	    "\t-m mode     L2CAP link mode (NOT YET SUPPORTED)\n"
+	    "\t-p psm      L2CAP PSM\n"
+	    "\t-S service  service name (no SDP)\n"
+	    "\t-s service  service name\n"
+	    "\n"
+	    "Known services:\n"
+	    "", p, n, "", p, n, "");
+
+	for (n = 0; n < __arraycount(services); n++)
+		fprintf(stderr, "\t%s\t%s\n", services[n].name, services[n].desc);
+
+	exit(EXIT_FAILURE);
+}
diff --git a/usr.sbin/btpand/btpand.h b/usr.sbin/btpand/btpand.h
new file mode 100644
index 0000000000..5edbf16eeb
--- /dev/null
+++ b/usr.sbin/btpand/btpand.h
@@ -0,0 +1,212 @@
+/*	$NetBSD: btpand.h,v 1.1 2008/08/17 13:20:57 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/btpand.h 188013 2009-02-02 18:08:22Z emax $ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+
+#include <assert.h>
+#include <bluetooth.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "event.h"
+
+#ifndef __arraycount
+#define __arraycount(__x)	(int)(sizeof((__x)) / sizeof((__x)[0]))
+#endif
+
+#ifndef	L2CAP_PSM_INVALID
+#define	L2CAP_PSM_INVALID(psm)	(((psm) & 0x0101) != 0x0001)
+#endif
+
+#ifndef	L2CAP_PSM_BNEP
+#define	L2CAP_PSM_BNEP	15
+#endif
+
+typedef struct channel	channel_t;
+typedef struct pfilter	pfilter_t;
+typedef struct mfilter	mfilter_t;
+typedef struct packet	packet_t;
+typedef struct pkthdr	pkthdr_t;
+typedef struct pktlist	pktlist_t;
+typedef struct exthdr	exthdr_t;
+typedef struct extlist	extlist_t;
+
+LIST_HEAD(chlist, channel);
+STAILQ_HEAD(extlist, exthdr);
+STAILQ_HEAD(pktlist, pkthdr);
+
+enum channel_state {
+	CHANNEL_CLOSED,
+	CHANNEL_WAIT_CONNECT_REQ,
+	CHANNEL_WAIT_CONNECT_RSP,
+	CHANNEL_OPEN,
+};
+
+#define CHANNEL_MAXQLEN		128
+
+/* BNEP or tap channel */
+struct channel {
+	enum channel_state	state;
+	bool			oactive;
+
+	uint8_t			laddr[ETHER_ADDR_LEN];
+	uint8_t			raddr[ETHER_ADDR_LEN];
+	size_t			mru;
+	size_t			mtu;
+
+	int			npfilter;
+	pfilter_t *		pfilter;
+
+	int			nmfilter;
+	mfilter_t *		mfilter;
+
+	pktlist_t		pktlist;
+	int			qlen;
+
+	int			fd;
+	struct event		rd_ev;
+	struct event		wr_ev;
+	uint8_t *		sendbuf;
+
+	bool			(*send)(channel_t *, packet_t *);
+	bool			(*recv)(packet_t *);
+
+	int			tick;
+
+	struct pidfh		*pfh;
+
+	int			refcnt;
+	LIST_ENTRY(channel)	next;
+};
+
+/* network protocol type filter */
+struct pfilter {
+	uint16_t	start;
+	uint16_t	end;
+};
+
+/* multicast address filter */
+struct mfilter {
+	uint8_t		start[ETHER_ADDR_LEN];
+	uint8_t		end[ETHER_ADDR_LEN];
+};
+
+/* packet data buffer */
+struct packet {
+	channel_t *		chan;	/* source channel */
+	uint8_t *		dst;	/* dest address */
+	uint8_t *		src;	/* source address */
+	uint8_t *		type;	/* protocol type */
+	uint8_t *		ptr;	/* data pointer */
+	size_t			len;	/* data length */
+	int			refcnt;	/* reference count */
+	extlist_t		extlist;/* extension headers */
+	uint8_t			buf[0];	/* data starts here */
+};
+
+/* extension header */
+struct exthdr {
+	STAILQ_ENTRY(exthdr)	next;
+	uint8_t *		ptr;
+	uint8_t			len;
+};
+
+/* packet header */
+struct pkthdr {
+	STAILQ_ENTRY(pkthdr)	next;
+	packet_t *		data;
+};
+
+/* global variables */
+extern const char *	control_path;
+extern const char *	service_name;
+extern const char *	interface_name;
+extern bdaddr_t		local_bdaddr;
+extern bdaddr_t		remote_bdaddr;
+extern uint16_t		l2cap_psm;
+extern int		l2cap_mode;
+extern uint16_t		service_class;
+extern int		server_limit;
+
+/*
+ * Bluetooth addresses are stored the other way around than
+ * Ethernet addresses even though they are of the same family
+ */
+static inline void
+b2eaddr(void *dst, bdaddr_t *src)
+{
+	uint8_t *d = dst;
+	int i;
+
+	for (i = 0; i < ETHER_ADDR_LEN; i++)
+		d[i] = src->b[ETHER_ADDR_LEN - i - 1];
+}
+
+#define log_err(fmt, args...)		syslog(LOG_ERR, fmt , ##args)
+#define log_info(fmt, args...)		syslog(LOG_INFO, fmt , ##args)
+#define log_notice(fmt, args...)	syslog(LOG_NOTICE, fmt , ##args)
+#define log_debug(fmt, args...)		syslog(LOG_DEBUG, "%s: " fmt, __func__ , ##args)
+
+/* bnep.c */
+bool		bnep_send(channel_t *, packet_t *);
+bool		bnep_recv(packet_t *);
+void		bnep_send_control(channel_t *, uint8_t, ...);
+
+/* channel.c */
+void		channel_init(void);
+channel_t *	channel_alloc(void);
+bool		channel_open(channel_t *, int);
+void		channel_close(channel_t *);
+void		channel_free(channel_t *);
+void		channel_timeout(channel_t *, int);
+void		channel_put(channel_t *, packet_t *);
+
+/* client.c */
+void		client_init(void);
+
+/* packet.c */
+packet_t *	packet_alloc(channel_t *);
+void		packet_free(packet_t *);
+void		packet_adj(packet_t *, size_t);
+pkthdr_t *	pkthdr_alloc(packet_t *);
+void		pkthdr_free(pkthdr_t *);
+
+/* server.c */
+void		server_init(void);
+void		server_update(int);
+
+/* tap.c */
+void		tap_init(void);
diff --git a/usr.sbin/btpand/channel.c b/usr.sbin/btpand/channel.c
new file mode 100644
index 0000000000..df954c3d57
--- /dev/null
+++ b/usr.sbin/btpand/channel.c
@@ -0,0 +1,335 @@
+/*	$NetBSD: channel.c,v 1.1 2008/08/17 13:20:57 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/channel.c 187938 2009-01-30 22:23:21Z emax $ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: channel.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <libutil.h>
+#include <unistd.h>
+
+#include "btpand.h"
+
+static struct chlist	channel_list;
+static int		channel_count;
+static int		channel_tick;
+
+static void channel_start(int, short, void *);
+static void channel_read(int, short, void *);
+static void channel_dispatch(packet_t *);
+static void channel_watchdog(int, short, void *);
+
+void
+channel_init(void)
+{
+
+	LIST_INIT(&channel_list);
+}
+
+channel_t *
+channel_alloc(void)
+{
+	channel_t *chan;
+
+	chan = malloc(sizeof(channel_t));
+	if (chan == NULL) {
+		log_err("%s() failed: %m", __func__);
+		return NULL;
+	}
+
+	memset(chan, 0, sizeof(channel_t));
+	STAILQ_INIT(&chan->pktlist);
+	chan->state = CHANNEL_CLOSED;
+	LIST_INSERT_HEAD(&channel_list, chan, next);
+
+	server_update(++channel_count);
+
+	return chan;
+}
+
+bool
+channel_open(channel_t *chan, int fd)
+{
+	int n;
+
+	assert(chan->refcnt == 0);
+	assert(chan->state != CHANNEL_CLOSED);
+
+	if (chan->mtu > 0) {
+		chan->sendbuf = malloc(chan->mtu);
+		if (chan->sendbuf == NULL) {
+			log_err("Could not malloc channel sendbuf: %m");
+			return false;
+		}
+	}
+
+	n = 1;
+	if (ioctl(fd, FIONBIO, &n) == -1) {
+		log_err("Could not set non-blocking IO: %m");
+		return false;
+	}
+
+	event_set(&chan->rd_ev, fd, EV_READ | EV_PERSIST, channel_read, chan);
+	if (event_add(&chan->rd_ev, NULL) == -1) {
+		log_err("Could not add channel read event: %m");
+		return false;
+	}
+
+	event_set(&chan->wr_ev, fd, EV_WRITE, channel_start, chan);
+
+	chan->refcnt++;
+	chan->fd = fd;
+
+	log_debug("(fd#%d)", chan->fd);
+
+	return true;
+}
+
+void
+channel_close(channel_t *chan)
+{
+	pkthdr_t *ph;
+
+	assert(chan->state != CHANNEL_CLOSED);
+
+	log_debug("(fd#%d)", chan->fd);
+
+	chan->state = CHANNEL_CLOSED;
+	event_del(&chan->rd_ev);
+	event_del(&chan->wr_ev);
+	close(chan->fd);
+	chan->refcnt--;
+	chan->tick = 0;
+
+	while ((ph = STAILQ_FIRST(&chan->pktlist)) != NULL) {
+		STAILQ_REMOVE_HEAD(&chan->pktlist, next);
+		pkthdr_free(ph);
+		chan->qlen--;
+	}
+
+	if (chan->pfh != NULL) {
+		pidfile_remove(chan->pfh);
+		chan->pfh = NULL;
+	}
+
+	if (chan->refcnt == 0)
+		channel_free(chan);
+}
+
+void
+channel_free(channel_t *chan)
+{
+
+	assert(chan->refcnt == 0);
+	assert(chan->state == CHANNEL_CLOSED);
+	assert(chan->qlen == 0);
+	assert(STAILQ_EMPTY(&chan->pktlist));
+
+	LIST_REMOVE(chan, next);
+	free(chan->pfilter);
+	free(chan->mfilter);
+	free(chan->sendbuf);
+	free(chan);
+
+	server_update(--channel_count);
+
+	if (server_limit == 0) {
+		log_info("connection closed, exiting");
+		exit(EXIT_SUCCESS);
+	}
+}
+
+static void
+channel_start(int fd, short ev, void *arg)
+{
+	channel_t *chan = arg;
+	pkthdr_t *ph;
+
+	chan->oactive = true;
+
+	while (chan->qlen > 0) {
+		ph = STAILQ_FIRST(&chan->pktlist);
+
+		channel_timeout(chan, 10);
+		if (chan->send(chan, ph->data) == false) {
+			if (event_add(&chan->wr_ev, NULL) == -1) {
+				log_err("Could not add channel write event: %m");
+				channel_close(chan);
+			}
+			return;
+		}
+
+		STAILQ_REMOVE_HEAD(&chan->pktlist, next);
+		pkthdr_free(ph);
+		chan->qlen--;
+	}
+
+	channel_timeout(chan, 0);
+	chan->oactive = false;
+}
+
+static void
+channel_read(int fd, short ev, void *arg)
+{
+	channel_t *chan = arg;
+	packet_t *pkt;
+	ssize_t nr;
+
+	pkt = packet_alloc(chan);
+	if (pkt == NULL) {
+		channel_close(chan);
+		return;
+	}
+
+	nr = read(fd, pkt->buf, chan->mru);
+	if (nr == -1) {
+		log_err("channel read error: %m");
+		packet_free(pkt);
+		channel_close(chan);
+		return;
+	}
+	if (nr == 0) {	/* EOF */
+		log_debug("(fd#%d) EOF", fd);
+		packet_free(pkt);
+		channel_close(chan);
+		return;
+	}
+	pkt->len = nr;
+
+	if (chan->recv(pkt) == true)
+		channel_dispatch(pkt);
+
+	packet_free(pkt);
+}
+
+static void
+channel_dispatch(packet_t *pkt)
+{
+	channel_t *chan;
+
+	/*
+	 * This is simple routing. I'm not sure if its allowed by
+	 * the PAN or BNEP specifications, but it seems logical
+	 * to send unicast packets to connected destinations where
+	 * possible.
+	 */
+	if (!ETHER_IS_MULTICAST(pkt->dst)) {
+		LIST_FOREACH(chan, &channel_list, next) {
+			if (chan == pkt->chan
+			    || chan->state != CHANNEL_OPEN)
+				continue;
+
+			if (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) == 0) {
+				if (chan->qlen > CHANNEL_MAXQLEN)
+					log_notice("Queue overflow");
+				else
+					channel_put(chan, pkt);
+
+				return;
+			}
+		}
+	}
+
+	LIST_FOREACH(chan, &channel_list, next) {
+		if (chan == pkt->chan
+		    || chan->state != CHANNEL_OPEN)
+			continue;
+
+		if (chan->qlen > CHANNEL_MAXQLEN) {
+			log_notice("Queue overflow");
+			continue;
+		}
+
+		channel_put(chan, pkt);
+	}
+}
+
+void
+channel_put(channel_t *chan, packet_t *pkt)
+{
+	pkthdr_t *ph;
+
+	ph = pkthdr_alloc(pkt);
+	if (ph == NULL)
+		return;
+
+	chan->qlen++;
+	STAILQ_INSERT_TAIL(&chan->pktlist, ph, next);
+
+	if (!chan->oactive)
+		channel_start(chan->fd, EV_WRITE, chan);
+}
+
+/*
+ * Simple watchdog timer, only ticks when it is required and
+ * closes the channel down if it times out.
+ */
+void
+channel_timeout(channel_t *chan, int to)
+{
+	static struct event ev;
+
+	if (to == 0)
+		chan->tick = 0;
+	else
+		chan->tick = (channel_tick + to) % 60;
+
+	if (channel_tick == 0) {
+		evtimer_set(&ev, channel_watchdog, &ev);
+		channel_watchdog(0, 0, &ev);
+	}
+}
+
+static void
+channel_watchdog(int fd, short ev, void *arg)
+{
+	static struct timeval tv = { .tv_sec = 1 };
+	channel_t *chan, *next;
+	int tick;
+
+	tick = (channel_tick % 60) + 1;
+	channel_tick = 0;
+
+	next = LIST_FIRST(&channel_list);
+	while ((chan = next) != NULL) {
+		next = LIST_NEXT(chan, next);
+
+		if (chan->tick == tick)
+			channel_close(chan);
+		else if (chan->tick != 0)
+			channel_tick = tick;
+	}
+
+	if (channel_tick != 0 && evtimer_add(arg, &tv) < 0) {
+		log_err("Could not add watchdog event: %m");
+		exit(EXIT_FAILURE);
+	}
+}
diff --git a/usr.sbin/btpand/client.c b/usr.sbin/btpand/client.c
new file mode 100644
index 0000000000..a6edfb87f8
--- /dev/null
+++ b/usr.sbin/btpand/client.c
@@ -0,0 +1,224 @@
+/*	$NetBSD: client.c,v 1.2 2008/12/06 20:01:14 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/client.c 241699 2012-10-18 16:34:00Z emax $ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: client.c,v 1.2 2008/12/06 20:01:14 plunky Exp $");
+
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <unistd.h>
+
+#include "btpand.h"
+#include "bnep.h"
+#include "sdp.h"
+
+static void client_query(void);
+
+void
+client_init(void)
+{
+	struct sockaddr_l2cap sa;
+	channel_t *chan;
+	socklen_t len;
+	int fd, n;
+	uint16_t mru, mtu;
+
+	if (bdaddr_any(&remote_bdaddr))
+		return;
+
+	if (service_name)
+		client_query();
+
+	fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
+	if (fd == -1) {
+		log_err("Could not open L2CAP socket: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&sa, 0, sizeof(sa));
+	sa.l2cap_family = AF_BLUETOOTH;
+	sa.l2cap_len = sizeof(sa);
+	bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr);
+	if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
+		log_err("Could not bind client socket: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	mru = BNEP_MTU_MIN;
+	if (setsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, sizeof(mru)) == -1) {
+		log_err("Could not set L2CAP IMTU (%d): %m", mru);
+		exit(EXIT_FAILURE);
+	}
+
+	log_info("Opening connection to service 0x%4.4x at %s",
+	    service_class, bt_ntoa(&remote_bdaddr, NULL));
+
+	sa.l2cap_psm = htole16(l2cap_psm);
+	bdaddr_copy(&sa.l2cap_bdaddr, &remote_bdaddr);
+	if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
+		log_err("Could not connect: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	len = sizeof(mru);
+	if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, &len) == -1) {
+		log_err("Could not get IMTU: %m");
+		exit(EXIT_FAILURE);
+	}
+	if (mru < BNEP_MTU_MIN) {
+		log_err("L2CAP IMTU too small (%d)", mru);
+		exit(EXIT_FAILURE);
+	}
+
+	len = sizeof(n);
+	if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, &len) == -1) {
+		log_err("Could not read SO_RCVBUF");
+		exit(EXIT_FAILURE);
+	}
+	if (n < (mru * 10)) {
+		n = mru * 10;
+		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
+			log_info("Could not increase SO_RCVBUF (from %d)", n);
+	}
+
+	len = sizeof(mtu);
+	if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_OMTU, &mtu, &len) == -1) {
+		log_err("Could not get L2CAP OMTU: %m");
+		exit(EXIT_FAILURE);
+	}
+	if (mtu < BNEP_MTU_MIN) {
+		log_err("L2CAP OMTU too small (%d)", mtu);
+		exit(EXIT_FAILURE);
+	}
+
+	len = sizeof(n);
+	if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, &len) == -1) {
+		log_err("Could not get socket send buffer size: %m");
+		close(fd);
+		return;
+	}
+	if (n < (mtu * 2)) {
+		n = mtu * 2;
+		if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) == -1) {
+			log_err("Could not set socket send buffer size (%d): %m", n);
+			close(fd);
+			return;
+		}
+	}
+	n = mtu;
+	if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &n, sizeof(n)) == -1) {
+		log_err("Could not set socket low water mark (%d): %m", n);
+		close(fd);
+		return;
+	}
+
+	chan = channel_alloc();
+	if (chan == NULL)
+		exit(EXIT_FAILURE);
+
+	chan->send = bnep_send;
+	chan->recv = bnep_recv;
+	chan->mru = mru;
+	chan->mtu = mtu;
+	b2eaddr(chan->raddr, &remote_bdaddr);
+	b2eaddr(chan->laddr, &local_bdaddr);
+	chan->state = CHANNEL_WAIT_CONNECT_RSP;
+	channel_timeout(chan, 10);
+	if (!channel_open(chan, fd))
+		exit(EXIT_FAILURE);
+
+	bnep_send_control(chan, BNEP_SETUP_CONNECTION_REQUEST,
+	    2, service_class, SDP_SERVICE_CLASS_PANU);
+}
+
+static void
+client_query(void)
+{
+	uint8_t buffer[512];
+	sdp_attr_t attr;
+	uint32_t range;
+	void *ss;
+	int rv;
+	uint8_t *seq0, *seq1;
+
+	attr.flags = SDP_ATTR_INVALID;
+	attr.attr = 0;
+	attr.vlen = sizeof(buffer);
+	attr.value = buffer;
+
+	range = SDP_ATTR_RANGE(SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+			       SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
+
+	ss = sdp_open(&local_bdaddr, &remote_bdaddr);
+	if (ss == NULL || (errno = sdp_error(ss)) != 0) {
+		log_err("%s: %m", service_name);
+		exit(EXIT_FAILURE);
+	}
+
+	log_info("Searching for %s service at %s",
+	    service_name, bt_ntoa(&remote_bdaddr, NULL));
+
+	rv = sdp_search(ss, 1, &service_class, 1, &range, 1, &attr);
+	if (rv != 0) {
+		log_err("%s: %s", service_name, strerror(sdp_error(ss)));
+		exit(EXIT_FAILURE);
+	}
+
+	sdp_close(ss);
+
+	if (attr.flags != SDP_ATTR_OK
+	    || attr.attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST) {
+		log_err("%s service not found", service_name);
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * we expect the following protocol descriptor list
+	 *
+	 *	seq len
+	 *	  seq len
+	 *	    uuid value == L2CAP
+	 *	    uint16 value16 => PSM
+	 *	  seq len
+	 *	    uuid value == BNEP
+	 */
+	if (_sdp_get_seq(&attr.value, attr.value + attr.vlen, &seq0)
+	    && _sdp_get_seq(&seq0, attr.value, &seq1)
+	    && _sdp_match_uuid16(&seq1, seq0, SDP_UUID_PROTOCOL_L2CAP)
+	    && _sdp_get_uint16(&seq1, seq0, &l2cap_psm)
+	    && _sdp_get_seq(&seq0, attr.value, &seq1)
+	    && _sdp_match_uuid16(&seq1, seq0, SDP_UUID_PROTOCOL_BNEP)) {
+		log_info("Found PSM %d for service %s", l2cap_psm, service_name);
+		return;
+	}
+
+	log_err("%s query failed", service_name);
+	exit(EXIT_FAILURE);
+}
diff --git a/usr.sbin/btpand/event.c b/usr.sbin/btpand/event.c
new file mode 100644
index 0000000000..19e8458bb5
--- /dev/null
+++ b/usr.sbin/btpand/event.c
@@ -0,0 +1,309 @@
+/*
+ * event.h
+ */
+
+/*-
+ * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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: head/usr.sbin/bluetooth/btpand/event.c 191232 2009-04-17 23:33:30Z emax $ */
+
+/*
+ * Hack to provide libevent (see devel/libevent port) like API.
+ * Should be removed if FreeBSD ever decides to import libevent into base.
+ */
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "event.h"
+#include "btpand.h"
+
+#define		__event_link(ev) \
+do { \
+		TAILQ_INSERT_TAIL(&pending, ev, next); \
+		ev->flags |= EV_PENDING; \
+} while (0)
+
+static void	tv_add(struct timeval *, struct timeval const *);
+static void	tv_sub(struct timeval *, struct timeval const *);
+static int	tv_cmp(struct timeval const *, struct timeval const *);
+static int	__event_dispatch(void);
+static void	__event_add_current(struct event *);
+static void	__event_del_current(struct event *);
+
+
+static TAILQ_HEAD(, event)	pending;
+static TAILQ_HEAD(, event)	current;
+
+void
+event_init(void)
+{
+	TAILQ_INIT(&pending);
+}
+
+int
+event_dispatch(void)
+{
+	while (__event_dispatch() == 0)
+		;
+
+	return (-1);
+}
+
+static int
+__event_dispatch(void)
+{
+	fd_set			r, w;
+	int			nfd;
+	struct event		*ev;
+	struct timeval		now, timeout, t;
+
+	FD_ZERO(&r);
+	FD_ZERO(&w);
+
+	nfd = 0;
+
+	gettimeofday(&now, NULL);
+
+	timeout.tv_sec = 10;	/* arbitrary */
+	timeout.tv_usec = 0;
+
+	TAILQ_INIT(&current);
+
+	/*
+	 * Build fd_set's
+	 */
+
+	event_log_debug("%s: building fd set...", __func__);
+
+	while (!TAILQ_EMPTY(&pending)) {
+		ev = TAILQ_FIRST(&pending);
+		event_del(ev);
+
+		if (ev->flags & EV_HAS_TIMEOUT) {
+			if (tv_cmp(&now, &ev->expire) >= 0)
+				t.tv_sec = t.tv_usec = 0;
+			else {
+				t = ev->expire;
+				tv_sub(&t, &now);
+			}
+
+			if (tv_cmp(&t, &timeout) < 0)
+				timeout = t;
+		}
+
+		if (ev->fd >= 0) {
+			if (ev->flags & EV_READ) {
+				FD_SET(ev->fd, &r);
+				nfd = (nfd > ev->fd) ? nfd : ev->fd;
+			}
+
+			if (ev->flags & EV_WRITE) {
+				FD_SET(ev->fd, &w);
+				nfd = (nfd > ev->fd) ? nfd : ev->fd;
+			}
+		}
+
+		__event_add_current(ev);
+	}
+
+	event_log_debug("%s: waiting for events...", __func__);
+
+	nfd = select(nfd + 1, &r, &w, NULL, &timeout);
+	if (nfd < 0)
+		return (-1);
+
+	/*
+	 * Process current pending
+	 */
+
+	event_log_debug("%s: processing events...", __func__);
+
+	gettimeofday(&now, NULL);
+
+	while (!TAILQ_EMPTY(&current)) {
+		ev = TAILQ_FIRST(&current);
+		__event_del_current(ev);
+
+		/* check if fd is ready for reading/writing */
+		if (nfd > 0 && ev->fd >= 0) {
+			if (FD_ISSET(ev->fd, &r) || FD_ISSET(ev->fd, &w)) {
+				if (ev->flags & EV_PERSIST) {
+					if (ev->flags & EV_HAS_TIMEOUT)
+						event_add(ev, &ev->timeout);
+					else
+						event_add(ev, NULL);
+				}
+
+				nfd --;
+
+				event_log_debug("%s: calling %p(%d, %p), " \
+					"ev=%p", __func__, ev->cb, ev->fd,
+					ev->cbarg, ev);
+
+				(ev->cb)(ev->fd,
+					(ev->flags & (EV_READ|EV_WRITE)),
+					ev->cbarg);
+
+				continue;
+			}
+		}
+
+		/* if event has no timeout - just requeue */
+		if ((ev->flags & EV_HAS_TIMEOUT) == 0) {
+			event_add(ev, NULL);
+			continue;
+		}
+
+		/* check if event has expired */
+		if (tv_cmp(&now, &ev->expire) >= 0) {
+			if (ev->flags & EV_PERSIST) 
+				event_add(ev, &ev->timeout);
+
+			event_log_debug("%s: calling %p(%d, %p), ev=%p",
+				__func__, ev->cb, ev->fd, ev->cbarg, ev);
+
+			(ev->cb)(ev->fd,
+				(ev->flags & (EV_READ|EV_WRITE)),
+				ev->cbarg);
+
+			continue;
+		}
+
+		assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0);
+		__event_link(ev);
+	}
+
+	return (0);
+}
+
+void
+__event_set(struct event *ev, int fd, short flags,
+	void (*cb)(int, short, void *), void *cbarg)
+{
+	ev->fd = fd;
+	ev->flags = flags;
+	ev->cb = cb;
+	ev->cbarg = cbarg;
+}
+
+int
+__event_add(struct event *ev, const struct timeval *timeout)
+{
+	assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0);
+
+	if (timeout != NULL) {
+		gettimeofday(&ev->expire, NULL);
+		tv_add(&ev->expire, timeout);
+		ev->timeout = *timeout;
+		ev->flags |= EV_HAS_TIMEOUT;
+	} else
+		ev->flags &= ~EV_HAS_TIMEOUT;
+
+	__event_link(ev);
+
+	return (0);
+}
+
+int
+__event_del(struct event *ev)
+{
+	assert((ev->flags & EV_CURRENT) == 0);
+
+	if ((ev->flags & EV_PENDING) != 0) {
+		TAILQ_REMOVE(&pending, ev, next);
+		ev->flags &= ~EV_PENDING;
+	}
+
+	return (0);
+}
+
+static void
+__event_add_current(struct event *ev)
+{
+	assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0);
+
+	TAILQ_INSERT_TAIL(&current, ev, next);
+	ev->flags |= EV_CURRENT;
+}
+
+static void
+__event_del_current(struct event *ev)
+{
+	assert((ev->flags & (EV_CURRENT|EV_PENDING)) == EV_CURRENT);
+
+	TAILQ_REMOVE(&current, ev, next);
+	ev->flags &= ~EV_CURRENT;
+}
+
+static void
+tv_add(struct timeval *a, struct timeval const *b)
+{
+	a->tv_sec += b->tv_sec;
+	a->tv_usec += b->tv_usec;
+
+	if(a->tv_usec >= 1000000) {
+		a->tv_usec -= 1000000;
+		a->tv_sec += 1;
+	}
+}
+
+static void
+tv_sub(struct timeval *a, struct timeval const *b)
+{
+	if (a->tv_usec < b->tv_usec) {
+		a->tv_usec += 1000000;
+		a->tv_sec -= 1;
+	}
+
+	a->tv_usec -= b->tv_usec;
+	a->tv_sec -= b->tv_sec;
+}
+
+static int
+tv_cmp(struct timeval const *a, struct timeval const *b)
+{
+ 	if (a->tv_sec > b->tv_sec)
+		return (1);
+
+	if (a->tv_sec < b->tv_sec)
+		return (-1);
+
+	if (a->tv_usec > b->tv_usec)
+		return (1);
+
+	if (a->tv_usec < b->tv_usec)
+		return (-1);
+
+	return (0);
+}
+
diff --git a/usr.sbin/btpand/event.h b/usr.sbin/btpand/event.h
new file mode 100644
index 0000000000..2c94549636
--- /dev/null
+++ b/usr.sbin/btpand/event.h
@@ -0,0 +1,147 @@
+/*
+ * event.h
+ */
+
+/*-
+ * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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: head/usr.sbin/bluetooth/btpand/event.h 228990 2011-12-30 10:58:14Z uqs $ */
+
+/*
+ * Hack to provide libevent (see devel/libevent port) like API.
+ * Should be removed if FreeBSD ever decides to import libevent into base.
+ */
+
+#ifndef	_EVENT_H_
+#define	_EVENT_H_	1
+
+#define	EV_READ         0x02
+#define	EV_WRITE        0x04
+#define	EV_PERSIST      0x10		/* Persistent event */
+#define	EV_PENDING	(1 << 13)	/* internal use only! */
+#define	EV_HAS_TIMEOUT	(1 << 14)	/* internal use only! */
+#define	EV_CURRENT	(1 << 15)	/* internal use only! */
+
+struct event
+{
+	int			fd;
+	short			flags;
+	void			(*cb)(int, short, void *);
+	void			*cbarg;
+	struct timeval		timeout;
+	struct timeval		expire;
+
+#ifdef	EVENT_DEBUG
+	char const		*files[3];
+	int			lines[3];
+#endif
+
+	TAILQ_ENTRY(event)	next;
+};
+
+void	event_init	(void);
+int	event_dispatch	(void);
+
+void	__event_set	(struct event *, int, short,
+			 void (*)(int, short, void *), void *);
+int	__event_add	(struct event *, struct timeval const *);
+int	__event_del	(struct event *);
+
+#ifdef	EVENT_DEBUG
+#define event_log_err(fmt, args...)	syslog(LOG_ERR, fmt, ##args)
+#define event_log_info(fmt, args...)	syslog(LOG_INFO, fmt, ##args)
+#define event_log_notice(fmt, args...)	syslog(LOG_NOTICE, fmt, ##args)
+#define event_log_debug(fmt, args...)	syslog(LOG_DEBUG, fmt, ##args)
+
+#define	event_set(ev, fd, flags, cb, cbarg) \
+	_event_set(__FILE__, __LINE__, ev, fd, flags, cb, cbarg)
+#define	event_add(ev, timeout) \
+	_event_add(__FILE__, __LINE__, ev, timeout)
+#define	event_del(ev) \
+	_event_del(__FILE__, __LINE__, ev)
+
+#define	evtimer_set(ev, cb, cbarg) \
+	_event_set(__FILE__, __LINE__, ev, -1, 0, cb, cbarg)
+#define	evtimer_add(ev, timeout) \
+	_event_add(__FILE__, __LINE__, ev, timeout)
+
+static inline void
+_event_set(char const *file, int line, struct event *ev, int fd, short flags,
+		void (*cb)(int, short, void *), void *cbarg)
+{
+	event_log_debug("set %s:%d ev=%p, fd=%d, flags=%#x, cb=%p, cbarg=%p",
+		file, line, ev, fd, flags, cb, cbarg);
+
+	ev->files[0] = file;
+	ev->lines[0] = line;
+
+	__event_set(ev, fd, flags, cb, cbarg);
+}
+
+static inline int
+_event_add(char const *file, int line, struct event *ev,
+		struct timeval const *timeout) {
+	event_log_debug("add %s:%d ev=%p, fd=%d, flags=%#x, cb=%p, cbarg=%p, " \
+		"timeout=%p", file, line, ev, ev->fd, ev->flags, ev->cb,
+		ev->cbarg, timeout);
+
+	ev->files[1] = file;
+	ev->lines[1] = line;
+
+	return (__event_add(ev, timeout));
+}
+
+static inline int
+_event_del(char const *file, int line, struct event *ev)
+{
+	event_log_debug("del %s:%d ev=%p, fd=%d, flags=%#x, cb=%p, cbarg=%p",
+		file, line, ev, ev->fd, ev->flags, ev->cb, ev->cbarg);
+
+	ev->files[2] = file;
+	ev->lines[2] = line;
+
+	return (__event_del(ev));
+}
+#else
+#define event_log_err(fmt, args...)
+#define event_log_info(fmt, args...)
+#define event_log_notice(fmt, args...)
+#define event_log_debug(fmt, args...)
+
+#define	event_set(ev, fd, flags, cb, cbarg) \
+	__event_set(ev, fd, flags, cb, cbarg)
+#define	event_add(ev, timeout) \
+	__event_add(ev, timeout)
+#define	event_del(ev) \
+	__event_del(ev)
+
+#define	evtimer_set(ev, cb, cbarg) \
+	__event_set(ev, -1, 0, cb, cbarg)
+#define	evtimer_add(ev, timeout) \
+	__event_add(ev, timeout)
+#endif	/* EVENT_DEBUG */
+
+#endif	/* ndef _EVENT_H_ */
diff --git a/usr.sbin/btpand/packet.c b/usr.sbin/btpand/packet.c
new file mode 100644
index 0000000000..c1422919d6
--- /dev/null
+++ b/usr.sbin/btpand/packet.c
@@ -0,0 +1,110 @@
+/*	$NetBSD: packet.c,v 1.1 2008/08/17 13:20:57 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/packet.c 187938 2009-01-30 22:23:21Z emax $ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: packet.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
+
+#include "btpand.h"
+
+packet_t *
+packet_alloc(channel_t *chan)
+{
+	packet_t *pkt;
+
+	pkt = malloc(sizeof(packet_t) + chan->mru);
+	if (pkt == NULL) {
+		log_err("%s() failed: %m", __func__);
+		return NULL;
+	}
+
+	memset(pkt, 0, sizeof(packet_t));
+	STAILQ_INIT(&pkt->extlist);
+	pkt->ptr = pkt->buf;
+
+	pkt->chan = chan;
+	chan->refcnt++;
+
+	return pkt;
+}
+
+void
+packet_free(packet_t *pkt)
+{
+	exthdr_t *eh;
+
+	if (pkt->refcnt-- > 0)
+		return;
+
+	while ((eh = STAILQ_FIRST(&pkt->extlist)) != NULL) {
+		STAILQ_REMOVE_HEAD(&pkt->extlist, next);
+		free(eh);
+	}
+
+	pkt->chan->refcnt--;
+	if (pkt->chan->refcnt == 0)
+		channel_free(pkt->chan);
+
+	free(pkt);
+}
+
+void
+packet_adj(packet_t *pkt, size_t size)
+{
+
+	assert(pkt->refcnt == 0);
+	assert(pkt->len >= size);
+
+	pkt->ptr += size;
+	pkt->len -= size;
+}
+
+pkthdr_t *
+pkthdr_alloc(packet_t *pkt)
+{
+	pkthdr_t *ph;
+
+	ph = malloc(sizeof(pkthdr_t));
+	if (ph == NULL) {
+		log_err("%s() failed: %m", __func__);
+		return NULL;
+	}
+
+	ph->data = pkt;
+	pkt->refcnt++;
+
+	return ph;
+}
+
+void
+pkthdr_free(pkthdr_t *ph)
+{
+
+	packet_free(ph->data);
+	free(ph);
+}
diff --git a/usr.sbin/btpand/sdp.c b/usr.sbin/btpand/sdp.c
new file mode 100644
index 0000000000..453f905880
--- /dev/null
+++ b/usr.sbin/btpand/sdp.c
@@ -0,0 +1,209 @@
+/*	$NetBSD: sdp.c,v 1.2 2008/12/06 20:01:14 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/sdp.c 187938 2009-01-30 22:23:21Z emax $ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: sdp.c,v 1.2 2008/12/06 20:01:14 plunky Exp $");
+
+#include <string.h>
+
+#include "sdp.h"
+
+/*
+ * SDP data stream manipulation routines
+ */
+
+/* Bluetooth Base UUID */
+static const uuid_t BASE_UUID = {
+	0x00000000,
+	0x0000,
+	0x1000,
+	0x80,
+	0x00,
+	{ 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb }
+};
+
+/*
+ * _sdp_match_uuid16(ptr, limit, uuid)
+ *
+ *	examine SDP data stream at ptr for a UUID, and return
+ *	true if it matches the supplied short alias bluetooth UUID.
+ *	limit is the first address past the end of valid data.
+ */
+bool
+_sdp_match_uuid16(uint8_t **ptr, uint8_t *limit, uint16_t uuid)
+{
+	uint8_t *p = *ptr;
+	uuid_t u1, u2;
+
+	memcpy(&u1, &BASE_UUID, sizeof(uuid_t));
+	u1.time_low = uuid;
+
+	if (!_sdp_get_uuid(&p, limit, &u2)
+	    || !uuid_equal(&u1, &u2, NULL))
+		return false;
+
+	*ptr = p;
+	return true;
+}
+
+/*
+ * _sdp_get_uuid(ptr, limit, uuid)
+ *
+ *	examine SDP data stream at ptr for a UUID, and extract
+ *	to given storage, advancing ptr.
+ *	limit is the first address past the end of valid data.
+ */
+bool
+_sdp_get_uuid(uint8_t **ptr, uint8_t *limit, uuid_t *uuid)
+{
+	uint8_t *p = *ptr;
+
+	if (p + 1 > limit)
+		return false;
+
+	switch (*p++) {
+	case SDP_DATA_UUID16:
+		if (p + 2 > limit)
+			return false;
+
+		memcpy(uuid, &BASE_UUID, sizeof(uuid_t));
+		uuid->time_low = be16dec(p);
+		p += 2;
+		break;
+
+	case SDP_DATA_UUID32:
+		if (p + 4 > limit)
+			return false;
+
+		memcpy(uuid, &BASE_UUID, sizeof(uuid_t));
+		uuid->time_low = be32dec(p);
+		p += 4;
+		break;
+
+	case SDP_DATA_UUID128:
+		if (p + 16 > limit)
+			return false;
+
+		uuid_dec_be(p, uuid);
+		p += 16;
+		break;
+
+	default:
+		return false;
+	}
+
+	*ptr = p;
+	return true;
+}
+
+/*
+ * _sdp_get_seq(ptr, limit, seq)
+ *
+ *	examine SDP data stream at ptr for a sequence. return
+ *	seq pointer if found and advance ptr to next object.
+ *	limit is the first address past the end of valid data.
+ */
+bool
+_sdp_get_seq(uint8_t **ptr, uint8_t *limit, uint8_t **seq)
+{
+	uint8_t *p = *ptr;
+	int32_t l;
+
+	if (p + 1 > limit)
+		return false;
+
+	switch (*p++) {
+	case SDP_DATA_SEQ8:
+		if (p + 1 > limit)
+			return false;
+
+		l = *p;
+		p += 1;
+		break;
+
+	case SDP_DATA_SEQ16:
+		if (p + 2 > limit)
+			return false;
+
+		l = be16dec(p);
+		p += 2;
+		break;
+
+	case SDP_DATA_SEQ32:
+		if (p + 4 > limit)
+			return false;
+
+		l = be32dec(p);
+		p += 4;
+		break;
+
+	default:
+		return false;
+	}
+	if (p + l > limit)
+		return false;
+
+	*seq = p;
+	*ptr = p + l;
+	return true;
+}
+
+/*
+ * _sdp_get_uint16(ptr, limit, value)
+ *
+ *	examine SDP data stream at ptr for a uint16_t, and
+ *	extract to given storage, advancing ptr.
+ *	limit is the first address past the end of valid data.
+ */
+bool
+_sdp_get_uint16(uint8_t **ptr, uint8_t *limit, uint16_t *value)
+{
+	uint8_t *p = *ptr;
+	uint16_t v;
+
+	if (p + 1 > limit)
+		return false;
+
+	switch (*p++) {
+	case SDP_DATA_UINT16:
+		if (p + 2 > limit)
+			return false;
+
+		v = be16dec(p);
+		p += 2;
+		break;
+
+	default:
+		return false;
+	}
+
+	*value = v;
+	*ptr = p;
+	return true;
+}
diff --git a/usr.sbin/btpand/sdp.h b/usr.sbin/btpand/sdp.h
new file mode 100644
index 0000000000..0409c9a7d2
--- /dev/null
+++ b/usr.sbin/btpand/sdp.h
@@ -0,0 +1,38 @@
+/*	$NetBSD: sdp.h,v 1.2 2008/12/06 20:01:15 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/sdp.h 187938 2009-01-30 22:23:21Z emax $ */
+
+#include <bluetooth.h>
+#include <sdp.h>
+#include <stdbool.h>
+#include <uuid.h>
+
+bool _sdp_match_uuid16(uint8_t **, uint8_t *, uint16_t);
+bool _sdp_get_uuid(uint8_t **, uint8_t *, uuid_t *);
+bool _sdp_get_seq(uint8_t **, uint8_t *, uint8_t **);
+bool _sdp_get_uint16(uint8_t **, uint8_t *, uint16_t *);
diff --git a/usr.sbin/btpand/server.c b/usr.sbin/btpand/server.c
new file mode 100644
index 0000000000..07d8287a7e
--- /dev/null
+++ b/usr.sbin/btpand/server.c
@@ -0,0 +1,289 @@
+/*	$NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/server.c 241699 2012-10-18 16:34:00Z emax $ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $");
+
+#include <sys/ioctl.h>
+
+#include <bluetooth.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sdp.h>
+#include <unistd.h>
+
+#include "btpand.h"
+#include "bnep.h"
+
+static struct event	server_ev;
+static int		server_fd;
+static int		server_avail;
+
+static void *		server_ss;
+static uint32_t		server_handle;
+
+static void server_open(void);
+static void server_close(void);
+static void server_read(int, short, void *);
+static void server_register(void);
+
+void
+server_init(void)
+{
+
+	server_fd = -1;
+}
+
+/*
+ * The server_update() function is called whenever the channel count is
+ * changed. We maintain the SDP record and open or close the server socket
+ * as required.
+ */
+void
+server_update(int count)
+{
+
+	if (server_limit == 0)
+		return;
+
+	log_debug("count %d", count);
+
+	server_avail = UINT8_MAX - (count - 1) * UINT8_MAX / server_limit;
+	log_info("Service Availability: %d/%d", server_avail, UINT8_MAX);
+
+	if (server_avail == 0 && server_fd != -1)
+		server_close();
+
+	if (server_avail > 0 && server_fd == -1)
+		server_open();
+
+	if (service_name)
+		server_register();
+}
+
+static void
+server_open(void)
+{
+	struct sockaddr_l2cap sa;
+	uint16_t mru;
+
+	server_fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
+	if (server_fd == -1) {
+		log_err("Could not open L2CAP socket: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&sa, 0, sizeof(sa));
+	sa.l2cap_family = AF_BLUETOOTH;
+	sa.l2cap_len = sizeof(sa);
+	sa.l2cap_psm = htole16(l2cap_psm);
+	bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr);
+	if (bind(server_fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
+		log_err("Could not bind server socket: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	mru = BNEP_MTU_MIN;
+	if (setsockopt(server_fd, SOL_L2CAP,
+	    SO_L2CAP_IMTU, &mru, sizeof(mru)) == -1) {
+		log_err("Could not set L2CAP IMTU (%d): %m", mru);
+		exit(EXIT_FAILURE);
+	}
+
+	if (listen(server_fd, 0) == -1) {
+		log_err("Could not listen on server socket: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	event_set(&server_ev, server_fd, EV_READ | EV_PERSIST, server_read, NULL);
+	if (event_add(&server_ev, NULL) == -1) {
+		log_err("Could not add server event: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	log_info("server socket open");
+}
+
+static void
+server_close(void)
+{
+
+	event_del(&server_ev);
+	close(server_fd);
+	server_fd = -1;
+
+	log_info("server socket closed");
+}
+
+/*
+ * handle connection request
+ */
+static void
+server_read(int s, short ev, void *arg)
+{
+	struct sockaddr_l2cap ra, la;
+	channel_t *chan;
+	socklen_t len;
+	int fd, n;
+	uint16_t mru, mtu;
+
+	len = sizeof(ra);
+	fd = accept(s, (struct sockaddr *)&ra, &len);
+	if (fd == -1)
+		return;
+
+	n = 1;
+	if (ioctl(fd, FIONBIO, &n) == -1) {
+		log_err("Could not set NonBlocking IO: %m");
+		close(fd);
+		return;
+	}
+
+	len = sizeof(mru);
+	if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, &len) == -1) {
+		log_err("Could not get L2CAP IMTU: %m");
+		close(fd);
+		return;
+	}
+	if(mru < BNEP_MTU_MIN) {
+		log_err("L2CAP IMTU too small (%d)", mru);
+		close(fd);
+		return;
+	}
+
+	len = sizeof(n);
+	if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, &len) == -1) {
+		log_err("Could not read SO_RCVBUF");
+		close(fd);
+		return;
+	}
+	if (n < (mru * 10)) {
+		n = mru * 10;
+		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
+			log_info("Could not increase SO_RCVBUF (from %d)", n);
+	}
+
+	len = sizeof(mtu);
+	if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_OMTU, &mtu, &len) == -1) {
+		log_err("Could not get L2CAP OMTU: %m");
+		close(fd);
+		return;
+	}
+	if (mtu < BNEP_MTU_MIN) {
+		log_err("L2CAP OMTU too small (%d)", mtu);
+		close(fd);
+		return;
+	}
+
+	len = sizeof(n);
+	if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, &len) == -1) {
+		log_err("Could not get socket send buffer size: %m");
+		close(fd);
+		return;
+	}
+
+	if (n < (mtu * 2)) {
+		n = mtu * 2;
+		if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) == -1) {
+			log_err("Could not set socket send buffer size (%d): %m", n);
+			close(fd);
+			return;
+		}
+	}
+
+	n = mtu;
+	if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &n, sizeof(n)) == -1) {
+		log_err("Could not set socket low water mark (%d): %m", n);
+		close(fd);
+		return;
+	}
+
+	len = sizeof(la);
+	if (getsockname(fd, (struct sockaddr *)&la, &len) == -1) {
+		log_err("Could not get socket address: %m");
+		close(fd);
+		return;
+	}
+
+	log_info("Accepted connection from %s", bt_ntoa(&ra.l2cap_bdaddr, NULL));
+
+	chan = channel_alloc();
+	if (chan == NULL) {
+		close(fd);
+		return;
+	}
+
+	chan->send = bnep_send;
+	chan->recv = bnep_recv;
+	chan->mru = mru;
+	chan->mtu = mtu;
+	b2eaddr(chan->raddr, &ra.l2cap_bdaddr);
+	b2eaddr(chan->laddr, &la.l2cap_bdaddr);
+	chan->state = CHANNEL_WAIT_CONNECT_REQ;
+	channel_timeout(chan, 10);
+	if (!channel_open(chan, fd)) {
+		chan->state = CHANNEL_CLOSED;
+		channel_free(chan);
+		close(fd);
+		return;
+	}
+}
+
+static void
+server_register(void)
+{
+	sdp_nap_profile_t p;
+	int rv;
+
+	if (server_ss == NULL) {
+		server_ss = sdp_open_local(control_path);
+		if (server_ss == NULL || sdp_error(server_ss) != 0) {
+			log_err("failed to contact SDP server");
+			return;
+		}
+	}
+
+	memset(&p, 0, sizeof(p));
+	p.psm = l2cap_psm;
+	p.load_factor = server_avail;
+	p.security_description = (l2cap_mode == 0 ? 0x0000 : 0x0001);
+
+	if (server_handle)
+		rv = sdp_change_service(server_ss, server_handle,
+		    (uint8_t *)&p, sizeof(p));
+	else
+		rv = sdp_register_service(server_ss, service_class,
+		    &local_bdaddr, (uint8_t *)&p, sizeof(p), &server_handle);
+
+	if (rv != 0) {
+		errno = sdp_error(server_ss);
+		log_err("%s: %m", service_name);
+		exit(EXIT_FAILURE);
+	}
+}
diff --git a/usr.sbin/btpand/tap.c b/usr.sbin/btpand/tap.c
new file mode 100644
index 0000000000..20eed6e35e
--- /dev/null
+++ b/usr.sbin/btpand/tap.c
@@ -0,0 +1,167 @@
+/*	$NetBSD: tap.c,v 1.1 2008/08/17 13:20:57 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * 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 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: head/usr.sbin/bluetooth/btpand/tap.c 187938 2009-01-30 22:23:21Z emax $ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: tap.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+
+#include <net/tap/if_tap.h>
+
+#include <fcntl.h>
+#include <libutil.h>
+#include <paths.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "btpand.h"
+
+static bool tap_send(channel_t *, packet_t *);
+static bool tap_recv(packet_t *);
+
+void
+tap_init(void)
+{
+	channel_t *chan;
+	struct ifreq ifr;
+	int fd, s;
+	char pidfile[PATH_MAX];
+
+	fd = open(interface_name, O_RDWR);
+	if (fd == -1) {
+		log_err("Could not open \"%s\": %m", interface_name);
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	if (ioctl(fd, TAPGIFNAME, &ifr) == -1) {
+		log_err("Could not get interface name: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s == -1) {
+		log_err("Could not open PF_LINK socket: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	ifr.ifr_addr.sa_family = AF_LINK;
+	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
+	b2eaddr(ifr.ifr_addr.sa_data, &local_bdaddr);
+
+	if (ioctl(s, SIOCSIFLLADDR, &ifr) == -1) {
+		log_err("Could not set %s physical address: %m", ifr.ifr_name);
+		exit(EXIT_FAILURE);
+	}
+
+	if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) {
+		log_err("Could not get interface flags: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	if ((ifr.ifr_flags & IFF_UP) == 0) {
+		ifr.ifr_flags |= IFF_UP;
+
+		if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) {
+			log_err("Could not set IFF_UP: %m");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	close(s);
+
+	log_info("Using interface %s with addr %s", ifr.ifr_name,
+		ether_ntoa((struct ether_addr *)&ifr.ifr_addr.sa_data));
+
+	chan = channel_alloc();
+	if (chan == NULL)
+		exit(EXIT_FAILURE);
+
+	chan->send = tap_send;
+	chan->recv = tap_recv;
+	chan->mru = ETHER_HDR_LEN + ETHER_MAX_LEN;
+	memcpy(chan->raddr, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
+	memcpy(chan->laddr, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
+	chan->state = CHANNEL_OPEN;
+	if (!channel_open(chan, fd))
+		exit(EXIT_FAILURE);
+
+	snprintf(pidfile, sizeof(pidfile), "%s/%s.pid",
+		_PATH_VARRUN, ifr.ifr_name);
+	chan->pfh = pidfile_open(pidfile, 0600, NULL);
+	if (chan->pfh == NULL)
+		log_err("can't create pidfile");
+	else if (pidfile_write(chan->pfh) < 0) {
+		log_err("can't write pidfile");
+		pidfile_remove(chan->pfh);
+		chan->pfh = NULL;
+	}
+}
+
+static bool
+tap_send(channel_t *chan, packet_t *pkt)
+{
+	struct iovec iov[4];
+	ssize_t nw;
+
+	iov[0].iov_base = pkt->dst;
+	iov[0].iov_len = ETHER_ADDR_LEN;
+	iov[1].iov_base = pkt->src;
+	iov[1].iov_len = ETHER_ADDR_LEN;
+	iov[2].iov_base = pkt->type;
+	iov[2].iov_len = ETHER_TYPE_LEN;
+	iov[3].iov_base = pkt->ptr;
+	iov[3].iov_len = pkt->len;
+
+	/* tap device write never fails */
+	nw = writev(chan->fd, iov, __arraycount(iov));
+	assert(nw > 0);
+
+	return true;
+}
+
+static bool
+tap_recv(packet_t *pkt)
+{
+
+	if (pkt->len < ETHER_HDR_LEN)
+		return false;
+
+	pkt->dst = pkt->ptr;
+	packet_adj(pkt, ETHER_ADDR_LEN);
+	pkt->src = pkt->ptr;
+	packet_adj(pkt, ETHER_ADDR_LEN);
+	pkt->type = pkt->ptr;
+	packet_adj(pkt, ETHER_TYPE_LEN);
+
+	return true;
+}
diff --git a/usr.sbin/hccontrol/Makefile b/usr.sbin/hccontrol/Makefile
new file mode 100644
index 0000000000..6b42ab4f6b
--- /dev/null
+++ b/usr.sbin/hccontrol/Makefile
@@ -0,0 +1,14 @@
+# $Id: Makefile,v 1.7 2003/08/14 20:06:17 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/hccontrol/Makefile 121054 2003-10-12 22:04:24Z emax $
+
+PROG=		hccontrol
+MAN=		hccontrol.8
+SRCS=		send_recv.c link_policy.c link_control.c \
+		host_controller_baseband.c info.c status.c node.c hccontrol.c \
+		util.c
+WARNS?=		2
+
+DPADD=		${LIBBLUETOOTH}
+LDADD=		-lbluetooth
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/hccontrol/hccontrol.8 b/usr.sbin/hccontrol/hccontrol.8
new file mode 100644
index 0000000000..e5831e9d34
--- /dev/null
+++ b/usr.sbin/hccontrol/hccontrol.8
@@ -0,0 +1,184 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: hccontrol.8,v 1.6 2003/08/06 21:26:38 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/hccontrol/hccontrol.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd June 14, 2002
+.Dt HCCONTROL 8
+.Os
+.Sh NAME
+.Nm hccontrol
+.Nd HCI configuration utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl hN
+.Op Fl n Ar HCI_node_name
+.Ar command
+.Op Ar parameters ...
+.Sh DESCRIPTION
+The
+.Nm
+utility connects to the specified Netgraph node of type
+.Dv HCI
+or the first one found if none is specified and attempts to send the specified
+command to the HCI Netgraph node or to the associated Bluetooth device.
+The
+.Nm
+utility will print results to the standard output and error messages to
+the standard error.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl h
+Display usage message and exit.
+.It Fl N
+Show Bluetooth addresses as numbers.
+Normally
+.Nm
+attempts to resolve Bluetooth addresses, and display them symbolically.
+.It Fl n Ar HCI_node_name
+Connect to the specified HCI Netgraph node.
+.It Ar command
+One of the supported commands (see below).
+The special command
+.Cm help
+can be used to obtain the list of all supported commands.
+To get more information about a specific command use
+.Cm help Ar command .
+.It Ar parameters
+One or more optional space separated command parameters.
+Many commands require a remote device address as one of the parameters.
+The remote device address can be specified as BD_ADDR or a name.
+If a name was specified then the
+.Nm
+utility will attempt to resolve the name via
+.Xr bt_gethostbyname 3 .
+.El
+.Sh COMMANDS
+The currently supported HCI commands in
+.Nm
+are:
+.Pp
+.Bl -tag -width 40n -offset indent -compact
+.It Cm Inquiry
+.It Cm Create_Connection
+.It Cm Disconnect
+.It Cm Add_SCO_Connection
+.It Cm Change_Connection_Packet_Type
+.It Cm Remote_Name_Request
+.It Cm Read_Remote_Supported_Features
+.It Cm Read_Remote_Version_Information
+.It Cm Read_Clock_Offset
+.It Cm Role_Discovery
+.It Cm Switch_Role
+.It Cm Read_Link_Policy_Settings
+.It Cm Write_Link_Policy_Settings
+.It Cm Reset
+.It Cm Read_Pin_Type
+.It Cm Write_Pin_Type
+.It Cm Read_Stored_Link_Key
+.It Cm Write_Stored_Link_Key
+.It Cm Delete_Stored_Link_Key
+.It Cm Change_Local_Name
+.It Cm Read_Local_Name
+.It Cm Read_Connection_Accept_Timeout
+.It Cm Write_Connection_Accept_Timeout
+.It Cm Read_Page_Timeout
+.It Cm Write_Page_Timeout
+.It Cm Read_Scan_Enable
+.It Cm Write_Scan_Enable
+.It Cm Read_Page_Scan_Activity
+.It Cm Write_Page_Scan_Activity
+.It Cm Read_Inquiry_Scan_Activity
+.It Cm Write_Inquiry_Scan_Activity
+.It Cm Read_Authentication_Enable
+.It Cm Write_Authentication_Enable
+.It Cm Read_Encryption_Mode
+.It Cm Write_Encryption_Mode
+.It Cm Read_Class_Of_Device
+.It Cm Write_Class_Of_Device
+.It Cm Read_Voice_Settings
+.It Cm Write_Voice_Settings
+.It Cm Read_Number_Broadcast_Retransmissions
+.It Cm Write_Number_Broadcast_Retransmissions
+.It Cm Read_Hold_Mode_Activity
+.It Cm Write_Hold_Mode_Activity
+.It Cm Read_SCO_Flow_Control_Enable
+.It Cm Write_SCO_Flow_Control_Enable
+.It Cm Read_Link_Supervision_Timeout
+.It Cm Write_Link_Supervision_Timeout
+.It Cm Read_Page_Scan_Period_Mode
+.It Cm Write_Page_Scan_Period_Mode
+.It Cm Read_Page_Scan_Mode
+.It Cm Write_Page_Scan_Mode
+.It Cm Read_Local_Version_Information
+.It Cm Read_Local_Supported_Features
+.It Cm Read_Buffer_Size
+.It Cm Read_Country_Code
+.It Cm Read_BD_ADDR
+.It Cm Read_Failed_Contact_Counter
+.It Cm Reset_Failed_Contact_Counter
+.It Cm Get_Link_Quality
+.It Cm Read_RSSI
+.El
+.Pp
+The currently supported node commands in
+.Nm
+are:
+.Pp
+.Bl -tag -width 40n -offset indent -compact
+.It Cm Read_Node_State
+.It Cm Initialize
+.It Cm Read_Debug_Level
+.It Cm Write_Debug_Level
+.It Cm Read_Node_Buffer_Size
+.It Cm Read_Node_BD_ADDR
+.It Cm Read_Node_Features
+.It Cm Read_Node_Stat
+.It Cm Reset_Node_Stat
+.It Cm Flush_Neighbor_Cache
+.It Cm Read_Neighbor_Cache
+.It Cm Read_Connection_List
+.It Cm Read_Node_Link_Policy_Settings_Mask
+.It Cm Write_Node_Link_Policy_Settings_Mask
+.It Cm Read_Node_Packet_Mask
+.It Cm Write_Node_Packet_Mask
+.It Cm Read_Node_Role_Switch
+.It Cm Write_Node_Role_Switch
+.It Cm Read_Node_List
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr bluetooth 3 ,
+.Xr netgraph 3 ,
+.Xr netgraph 4 ,
+.Xr ng_hci 4 ,
+.Xr hcseriald 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report if found.
diff --git a/usr.sbin/hccontrol/hccontrol.c b/usr.sbin/hccontrol/hccontrol.c
new file mode 100644
index 0000000000..cc47ea7950
--- /dev/null
+++ b/usr.sbin/hccontrol/hccontrol.c
@@ -0,0 +1,322 @@
+/*
+ * hccontrol.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: hccontrol.c,v 1.5 2003/09/05 00:38:24 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/hccontrol.c 159156 2006-06-02 00:29:01Z markus $
+ */
+
+#include <bluetooth.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <netgraph7/ng_message.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "hccontrol.h"
+
+/* Prototypes */
+static int                  do_hci_command    (char const *, int, char **);
+static struct hci_command * find_hci_command  (char const *, struct hci_command *);
+static int                  find_hci_nodes    (struct nodeinfo **);
+static void                 print_hci_command (struct hci_command *);
+static void usage                             (void);
+
+/* Globals */
+int	 verbose = 0; 
+int	 timeout;
+int	 numeric_bdaddr = 0;
+
+/* Main */
+int
+main(int argc, char *argv[])
+{
+	char	*node = NULL;
+	int	 n;
+
+	/* Process command line arguments */
+	while ((n = getopt(argc, argv, "n:Nvh")) != -1) {
+		switch (n) {
+		case 'n':
+			node = optarg;
+			break;
+
+		case 'N':
+			numeric_bdaddr = 1;
+			break;
+
+		case 'v':
+			verbose = 1;
+			break;
+
+		case 'h':
+		default:
+			usage();
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (*argv == NULL)
+		usage();
+
+	n = do_hci_command(node, argc, argv);
+
+	return (n);
+} /* main */
+
+/* Create socket and bind it */
+static int
+socket_open(char const *node)
+{
+	struct sockaddr_hci			 addr;
+	struct ng_btsocket_hci_raw_filter	 filter;
+	int					 s, mib[4], num;
+	size_t					 size;
+	struct nodeinfo 			*nodes;
+
+	num = find_hci_nodes(&nodes);
+	if (num == 0)
+		errx(7, "Could not find HCI nodes");
+
+	if (node == NULL) {
+		node = strdup(nodes[0].name);
+		if (num > 1)
+			fprintf(stdout, "Using HCI node: %s\n", node);
+	}
+
+	free(nodes);
+
+	s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
+	if (s < 0)
+		err(1, "Could not create socket");
+
+	memset(&addr, 0, sizeof(addr));
+	addr.hci_len = sizeof(addr);
+	addr.hci_family = AF_BLUETOOTH;
+	strncpy(addr.hci_node, node, sizeof(addr.hci_node));
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+		err(2, "Could not bind socket, node=%s", node);
+
+	if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+		err(3, "Could not connect socket, node=%s", node);
+
+	memset(&filter, 0, sizeof(filter));
+	bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_COMPL - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_RESULT - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_CON_COMPL - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_DISCON_COMPL - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_RETURN_LINK_KEYS - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_CON_PKT_TYPE_CHANGED - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_ROLE_CHANGE - 1);
+
+	if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER, 
+			(void * const) &filter, sizeof(filter)) < 0)
+		err(4, "Could not setsockopt()");
+
+	size = (sizeof(mib)/sizeof(mib[0]));
+	if (sysctlnametomib("net.bluetooth.hci.command_timeout",mib,&size) < 0)
+		err(5, "Could not sysctlnametomib()");
+
+	if (sysctl(mib, sizeof(mib)/sizeof(mib[0]),
+			(void *) &timeout, &size, NULL, 0) < 0)
+		err(6, "Could not sysctl()");
+
+	timeout ++;
+
+	return (s);
+} /* socket_open */
+
+/* Execute commands */
+static int
+do_hci_command(char const *node, int argc, char **argv)
+{
+	char			*cmd = argv[0];
+	struct hci_command	*c = NULL;
+	int			 s, e, help;
+	
+	help = 0;
+	if (strcasecmp(cmd, "help") == 0) {
+		argc --;
+		argv ++;
+
+		if (argc <= 0) {
+			fprintf(stdout, "Supported commands:\n");
+			print_hci_command(link_control_commands);
+			print_hci_command(link_policy_commands);
+			print_hci_command(host_controller_baseband_commands);
+			print_hci_command(info_commands);
+			print_hci_command(status_commands);
+			print_hci_command(node_commands);
+			fprintf(stdout, "\nFor more information use " \
+				"'help command'\n");
+
+			return (OK);
+		}
+
+		help = 1;
+		cmd = argv[0];
+	}
+
+	c = find_hci_command(cmd, link_control_commands);
+	if (c != NULL)
+		goto execute;
+
+	c = find_hci_command(cmd, link_policy_commands);
+	if (c != NULL)
+		goto execute;
+
+	c = find_hci_command(cmd, host_controller_baseband_commands);
+	if (c != NULL)
+		goto execute;
+
+	c = find_hci_command(cmd, info_commands);
+	if (c != NULL)
+		goto execute;
+
+	c = find_hci_command(cmd, status_commands);
+	if (c != NULL)
+		goto execute;
+
+	c = find_hci_command(cmd, node_commands);
+	if (c == NULL) {
+		fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
+		return (ERROR);
+	}
+execute:
+	if (!help) {
+		s = socket_open(node);
+		e = (c->handler)(s, -- argc, ++ argv);
+		close(s);
+	} else
+		e = USAGE;
+
+	switch (e) {
+	case OK:
+	case FAILED:
+		break;
+
+	case ERROR:
+		fprintf(stdout, "Could not execute command \"%s\". %s\n",
+			cmd, strerror(errno));
+		break;
+
+	case USAGE:
+		fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
+		break;
+
+	default: assert(0); break;
+	}
+
+
+	return (e);
+} /* do_hci_command */
+
+/* Try to find command in specified category */
+static struct hci_command *
+find_hci_command(char const *command, struct hci_command *category)
+{
+	struct hci_command	*c = NULL;
+
+	for (c = category; c->command != NULL; c++) {
+		char 	*c_end = strchr(c->command, ' ');
+
+		if (c_end != NULL) {
+			int	len = c_end - c->command;
+
+			if (strncasecmp(command, c->command, len) == 0)
+				return (c);
+		} else if (strcasecmp(command, c->command) == 0)
+				return (c);
+	}
+
+	return (NULL);
+} /* find_hci_command */
+
+/* Find all HCI nodes */
+static int
+find_hci_nodes(struct nodeinfo** nodes)
+{
+	struct ng_btsocket_hci_raw_node_list_names	r;
+	struct sockaddr_hci				addr;
+	int						s;
+	const char *					node = "ubt0hci";
+
+	r.num_names = MAX_NODE_NUM;
+	r.names = (struct nodeinfo*)calloc(MAX_NODE_NUM, sizeof(struct nodeinfo));
+	if (r.names == NULL)
+		err(8, "Could not allocate memory");
+
+	s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
+	if (s < 0)
+		err(9, "Could not create socket");
+
+	memset(&addr, 0, sizeof(addr));
+	addr.hci_len = sizeof(addr);
+	addr.hci_family = AF_BLUETOOTH;
+	strncpy(addr.hci_node, node, sizeof(addr.hci_node));
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+		err(10, "Could not bind socket");
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0)
+		err(11, "Could not get list of HCI nodes");
+
+	close(s);
+
+	*nodes = r.names;
+
+	return (r.num_names);
+} /* find_hci_nodes */
+
+/* Print commands in specified category */
+static void
+print_hci_command(struct hci_command *category)
+{
+	struct hci_command	*c = NULL;
+
+	for (c = category; c->command != NULL; c++)
+		fprintf(stdout, "\t%s\n", c->command);
+} /* print_hci_command */
+
+/* Usage */
+static void
+usage(void)
+{
+	fprintf(stdout, "Usage: hccontrol [-hN] [-n HCI_node_name] cmd [p1] [..]\n");
+	exit(255);
+} /* usage */
+
diff --git a/usr.sbin/hccontrol/hccontrol.h b/usr.sbin/hccontrol/hccontrol.h
new file mode 100644
index 0000000000..54a5eaa1bd
--- /dev/null
+++ b/usr.sbin/hccontrol/hccontrol.h
@@ -0,0 +1,79 @@
+/*
+ * hccontrol.h
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: hccontrol.h,v 1.2 2003/05/19 17:29:29 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/hccontrol.h 162495 2006-09-21 02:41:04Z emax $
+ */
+
+#ifndef _HCCONTROL_H_
+#define _HCCONTROL_H_
+
+#define	OK			0	/* everything was OK */
+#define	ERROR			1	/* could not execute command */
+#define	FAILED			2	/* error was reported */
+#define	USAGE			3	/* invalid parameters */
+
+#define	MAX_NODE_NUM		16	/* max number of nodes */
+
+struct hci_command {
+	char const		*command;
+	char const		*description;
+	int			(*handler)(int, int, char **);
+};
+
+extern int			 timeout;
+extern int			 verbose;
+extern struct hci_command	 link_control_commands[];
+extern struct hci_command	 link_policy_commands[];
+extern struct hci_command	 host_controller_baseband_commands[];
+extern struct hci_command	 info_commands[];
+extern struct hci_command	 status_commands[];
+extern struct hci_command	 node_commands[];
+ 
+int                hci_request         (int, int, char const *, int, char *, int *);
+int                hci_simple_request  (int, int, char *, int *);
+int                hci_send            (int, char const *, int);
+int                hci_recv            (int, char *, int *);
+
+char const *	hci_link2str        (int);
+char const *	hci_pin2str         (int);
+char const *	hci_scan2str        (int);
+char const *	hci_encrypt2str     (int, int);
+char const *	hci_coding2str      (int);
+char const *	hci_vdata2str       (int);
+char const *	hci_hmode2str       (int, char *, int);
+char const *	hci_ver2str         (int);
+char const *	hci_lmpver2str      (int);
+char const *	hci_manufacturer2str(int);
+char const *	hci_features2str    (uint8_t *, char *, int);
+char const *	hci_cc2str          (int);
+char const *	hci_con_state2str   (int);
+char const *	hci_status2str      (int);
+char const *	hci_bdaddr2str      (bdaddr_t const *);
+
+#endif /* _HCCONTROL_H_ */
+
diff --git a/usr.sbin/hccontrol/host_controller_baseband.c b/usr.sbin/hccontrol/host_controller_baseband.c
new file mode 100644
index 0000000000..eb74a98abc
--- /dev/null
+++ b/usr.sbin/hccontrol/host_controller_baseband.c
@@ -0,0 +1,1877 @@
+/*
+ * host_controller_baseband.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: host_controller_baseband.c,v 1.4 2003/08/18 19:19:53 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/host_controller_baseband.c 229075 2011-12-31 12:12:41Z stefanf $
+ */
+
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "hccontrol.h"
+
+/* Convert hex ASCII to int4 */
+static int
+hci_hexa2int4(const char *a)
+{
+	if ('0' <= *a && *a <= '9')
+		return (*a - '0');
+
+	if ('A' <= *a && *a <= 'F')
+		return (*a - 'A' + 0xa);
+
+	if ('a' <= *a && *a <= 'f')
+		return (*a - 'a' + 0xa);
+
+	return (-1);
+}
+
+/* Convert hex ASCII to int8 */
+static int
+hci_hexa2int8(const char *a)
+{
+	int	hi = hci_hexa2int4(a);
+	int	lo = hci_hexa2int4(a + 1);
+
+	if (hi < 0 || lo < 0)
+		return (-1);
+
+	return ((hi << 4) | lo);
+}
+
+/* Convert ascii hex string to the uint8_t[] */
+static int
+hci_hexstring2array(char const *s, uint8_t *a, int asize)
+{
+	int	i, l, b;
+
+	l = strlen(s) / 2;
+	if (l > asize)
+		l = asize;
+
+	for (i = 0; i < l; i++) {
+		b = hci_hexa2int8(s + i * 2);
+		if (b < 0)
+			return (-1);
+
+		a[i] = (b & 0xff);
+	}
+
+	return (0);
+}
+
+/* Send RESET to the unit */
+static int
+hci_reset(int s, int argc, char **argv)
+{
+	ng_hci_status_rp	rp;
+	int			n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_RESET), (char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n",
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_reset */
+
+/* Send Read_PIN_Type command to the unit */
+static int
+hci_read_pin_type(int s, int argc, char **argv)
+{
+	ng_hci_read_pin_type_rp	rp;
+	int			n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_PIN_TYPE),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "PIN type: %s [%#02x]\n",
+			hci_pin2str(rp.pin_type), rp.pin_type);
+
+	return (OK);
+} /* hci_read_pin_type */
+
+/* Send Write_PIN_Type command to the unit */
+static int
+hci_write_pin_type(int s, int argc, char **argv)
+{
+	ng_hci_write_pin_type_cp	cp;
+	ng_hci_write_pin_type_rp	rp;
+	int				n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 1)
+			return (USAGE);
+
+		cp.pin_type = (uint8_t) n;
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_PIN_TYPE),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp , &n) ==  ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_pin_type */
+
+/* Send Read_Stored_Link_Key command to the unit */
+static int
+hci_read_stored_link_key(int s, int argc, char **argv)
+{
+	struct {
+		ng_hci_cmd_pkt_t			hdr;
+		ng_hci_read_stored_link_key_cp		cp;
+	} __attribute__ ((packed))			cmd;
+
+	struct {
+		ng_hci_event_pkt_t			hdr;
+		union {
+			ng_hci_command_compl_ep		cc;
+			ng_hci_return_link_keys_ep	key;
+			uint8_t				b[NG_HCI_EVENT_PKT_SIZE];
+		}					ep;
+	} __attribute__ ((packed))			event;
+
+	int						n, n1;
+
+	/* Send command */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.type = NG_HCI_CMD_PKT;
+	cmd.hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+				NG_HCI_OCF_READ_STORED_LINK_KEY));
+	cmd.hdr.length = sizeof(cmd.cp);
+
+	switch (argc) {
+	case 1:
+		/* parse BD_ADDR */
+		if (!bt_aton(argv[0], &cmd.cp.bdaddr)) {
+			struct hostent	*he = NULL;
+
+			if ((he = bt_gethostbyname(argv[0])) == NULL)
+				return (USAGE);
+
+			memcpy(&cmd.cp.bdaddr, he->h_addr, sizeof(cmd.cp.bdaddr));
+		}
+		break;
+
+	default:
+		cmd.cp.read_all = 1;
+		break;
+	}
+
+	if (hci_send(s, (char const *) &cmd, sizeof(cmd)) != OK)
+		return (ERROR);
+
+	/* Receive events */
+again:
+	memset(&event, 0, sizeof(event));
+	n = sizeof(event);
+	if (hci_recv(s, (char *) &event, &n) != OK)
+		return (ERROR);
+
+	if (n <= sizeof(event.hdr)) {
+		errno = EMSGSIZE;
+		return (ERROR);
+	}
+
+	if (event.hdr.type != NG_HCI_EVENT_PKT) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	/* Parse event */
+	switch (event.hdr.event) {
+	case NG_HCI_EVENT_COMMAND_COMPL: {
+		ng_hci_read_stored_link_key_rp	*rp = NULL;
+
+		if (event.ep.cc.opcode == 0x0000 ||
+		    event.ep.cc.opcode != cmd.hdr.opcode)
+			goto again;
+
+		rp = (ng_hci_read_stored_link_key_rp *)(event.ep.b + 
+				sizeof(event.ep.cc));
+
+		fprintf(stdout, "Complete: Status: %s [%#x]\n", 
+				hci_status2str(rp->status), rp->status);
+		fprintf(stdout, "Maximum Number of keys: %d\n",
+				le16toh(rp->max_num_keys));
+		fprintf(stdout, "Number of keys read: %d\n",
+				le16toh(rp->num_keys_read));
+		} break;
+
+	case NG_HCI_EVENT_RETURN_LINK_KEYS: {
+		struct _key {
+			bdaddr_t	bdaddr;
+			uint8_t		key[NG_HCI_KEY_SIZE];
+		} __attribute__ ((packed))	*k = NULL;
+
+		fprintf(stdout, "Event: Number of keys: %d\n",
+			event.ep.key.num_keys);
+
+		k = (struct _key *)(event.ep.b + sizeof(event.ep.key));
+		for (n = 0; n < event.ep.key.num_keys; n++) {
+			fprintf(stdout, "\t%d: %s ",
+				n + 1, hci_bdaddr2str(&k->bdaddr));
+
+			for (n1 = 0; n1 < sizeof(k->key); n1++)
+				fprintf(stdout, "%02x", k->key[n1]);
+			fprintf(stdout, "\n");
+
+			k ++;
+		}
+
+		goto again;
+
+		} break;
+
+	default:
+		goto again;
+	}
+	
+	return (OK);
+} /* hci_read_store_link_key */
+
+/* Send Write_Stored_Link_Key command to the unit */
+static int
+hci_write_stored_link_key(int s, int argc, char **argv)
+{
+	struct {
+		ng_hci_write_stored_link_key_cp	p;
+		bdaddr_t			bdaddr;
+		uint8_t				key[NG_HCI_KEY_SIZE];
+	}					cp;
+	ng_hci_write_stored_link_key_rp		rp;
+	int32_t					n;
+
+	memset(&cp, 0, sizeof(cp));
+
+	switch (argc) {
+	case 2:
+		cp.p.num_keys_write = 1;
+
+		/* parse BD_ADDR */
+		if (!bt_aton(argv[0], &cp.bdaddr)) {
+			struct hostent	*he = NULL;
+
+			if ((he = bt_gethostbyname(argv[0])) == NULL)
+				return (USAGE);
+
+			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
+		}
+
+		/* parse key */
+		if (hci_hexstring2array(argv[1], cp.key, sizeof(cp.key)) < 0)
+			return (USAGE);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 
+			NG_HCI_OCF_WRITE_STORED_LINK_KEY),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Number of keys written: %d\n", rp.num_keys_written);
+
+	return (OK);
+} /* hci_write_stored_link_key */
+
+
+/* Send Delete_Stored_Link_Key command to the unit */
+static int
+hci_delete_stored_link_key(int s, int argc, char **argv)
+{
+	ng_hci_delete_stored_link_key_cp	cp;
+	ng_hci_delete_stored_link_key_rp	rp;
+	int32_t					n;
+
+	memset(&cp, 0, sizeof(cp));
+
+	switch (argc) {
+	case 1:
+		/* parse BD_ADDR */
+		if (!bt_aton(argv[0], &cp.bdaddr)) {
+			struct hostent	*he = NULL;
+
+			if ((he = bt_gethostbyname(argv[0])) == NULL)
+				return (USAGE);
+
+			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
+		}
+		break;
+
+	default:
+		cp.delete_all = 1;
+		break;
+	}
+
+	/* send command */
+	n = sizeof(cp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 
+			NG_HCI_OCF_DELETE_STORED_LINK_KEY),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Number of keys deleted: %d\n", rp.num_keys_deleted);
+
+	return (OK);
+} /* hci_delete_stored_link_key */
+
+/* Send Change_Local_Name command to the unit */
+static int
+hci_change_local_name(int s, int argc, char **argv) 
+{
+	ng_hci_change_local_name_cp	cp;
+	ng_hci_change_local_name_rp	rp;
+	int				n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		snprintf(cp.name, sizeof(cp.name), "%s", argv[0]);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 
+			NG_HCI_OCF_CHANGE_LOCAL_NAME),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_change_local_name */
+
+/* Send Read_Local_Name command to the unit */
+static int
+hci_read_local_name(int s, int argc, char **argv)
+{
+	ng_hci_read_local_name_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_LOCAL_NAME),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Local name: %s\n", rp.name);
+
+	return (OK);
+} /* hci_read_local_name */
+
+/* Send Read_Connection_Accept_Timeout to the unit */
+static int
+hci_read_connection_accept_timeout(int s, int argc, char **argv)
+{
+	ng_hci_read_con_accept_timo_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 
+			NG_HCI_OCF_READ_CON_ACCEPT_TIMO),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	rp.timeout = le16toh(rp.timeout);
+	fprintf(stdout, "Connection accept timeout: %.2f msec [%d slots]\n",
+			rp.timeout * 0.625, rp.timeout);
+					
+	return (OK);
+} /* hci_read_connection_accept_timeout */
+
+/* Send Write_Connection_Accept_Timeout to the unit */
+static int
+hci_write_connection_accept_timeout(int s, int argc, char **argv)
+{
+	ng_hci_write_con_accept_timo_cp	cp;
+	ng_hci_write_con_accept_timo_rp	rp;
+	int				n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 1 || n > 0xb540)
+			return (USAGE);
+
+		cp.timeout = (uint16_t) n;
+		cp.timeout = htole16(cp.timeout);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 
+			NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO),
+			(char const *) &cp, sizeof(cp), 
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n",
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_connection_accept_timeout */
+
+/* Send Read_Page_Timeout command to the unit */
+static int
+hci_read_page_timeout(int s, int argc, char **argv)
+{
+	ng_hci_read_page_timo_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_PAGE_TIMO),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	rp.timeout = le16toh(rp.timeout);
+	fprintf(stdout, "Page timeout: %.2f msec [%d slots]\n",
+		rp.timeout * 0.625, rp.timeout);
+
+	return (OK);
+} /* hci_read_page_timeoout */
+
+/* Send Write_Page_Timeout command to the unit */
+static int
+hci_write_page_timeout(int s, int argc, char **argv)
+{
+	ng_hci_write_page_timo_cp	cp;
+	ng_hci_write_page_timo_rp	rp;
+	int				n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 1 || n > 0xffff)
+			return (USAGE);
+
+		cp.timeout = (uint16_t) n;
+		cp.timeout = htole16(cp.timeout);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 
+			NG_HCI_OCF_WRITE_PAGE_TIMO),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_page_timeout */
+
+/* Send Read_Scan_Enable command to the unit */
+static int
+hci_read_scan_enable(int s, int argc, char **argv)
+{
+	ng_hci_read_scan_enable_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 
+			NG_HCI_OCF_READ_SCAN_ENABLE),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Scan enable: %s [%#02x]\n",
+		hci_scan2str(rp.scan_enable), rp.scan_enable);
+
+	return (OK);
+} /* hci_read_scan_enable */
+
+/* Send Write_Scan_Enable command to the unit */
+static int
+hci_write_scan_enable(int s, int argc, char **argv)
+{
+	ng_hci_write_scan_enable_cp	cp;
+	ng_hci_write_scan_enable_rp	rp;
+	int				n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 3)
+			return (USAGE);
+
+		cp.scan_enable = (uint8_t) n;
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, 
+			NG_HCI_OCF_WRITE_SCAN_ENABLE),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n",
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_scan_enable */
+
+/* Send Read_Page_Scan_Activity command to the unit */
+static int
+hci_read_page_scan_activity(int s, int argc, char **argv)
+{
+	ng_hci_read_page_scan_activity_rp	rp;
+	int					n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n",
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	rp.page_scan_interval = le16toh(rp.page_scan_interval);
+	rp.page_scan_window = le16toh(rp.page_scan_window);
+
+	fprintf(stdout, "Page Scan Interval: %.2f msec [%d slots]\n",
+		rp.page_scan_interval * 0.625, rp.page_scan_interval);
+	fprintf(stdout, "Page Scan Window: %.2f msec [%d slots]\n",
+		rp.page_scan_window * 0.625, rp.page_scan_window);
+
+	return (OK);
+} /* hci_read_page_scan_activity */
+
+/* Send Write_Page_Scan_Activity command to the unit */
+static int
+hci_write_page_scan_activity(int s, int argc, char **argv)
+{
+	ng_hci_write_page_scan_activity_cp	cp;
+	ng_hci_write_page_scan_activity_rp	rp;
+	int					n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 2:
+		/* page scan interval */
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
+			return (USAGE);
+
+		cp.page_scan_interval = (uint16_t) n;
+
+		/* page scan window */
+		if (sscanf(argv[1], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
+			return (USAGE);
+
+		cp.page_scan_window = (uint16_t) n;
+
+		if (cp.page_scan_window > cp.page_scan_interval)
+			return (USAGE);
+
+		cp.page_scan_interval = htole16(cp.page_scan_interval);
+		cp.page_scan_window = htole16(cp.page_scan_window);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_page_scan_activity */
+
+/* Send Read_Inquiry_Scan_Activity command to the unit */
+static int
+hci_read_inquiry_scan_activity(int s, int argc, char **argv)
+{
+	ng_hci_read_inquiry_scan_activity_rp	rp;
+	int					n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n",
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	rp.inquiry_scan_interval = le16toh(rp.inquiry_scan_interval);
+	rp.inquiry_scan_window = le16toh(rp.inquiry_scan_window);
+
+	fprintf(stdout, "Inquiry Scan Interval: %.2f msec [%d slots]\n",
+		rp.inquiry_scan_interval * 0.625, rp.inquiry_scan_interval);
+	fprintf(stdout, "Inquiry Scan Window: %.2f msec [%d slots]\n",
+		rp.inquiry_scan_window * 0.625, rp.inquiry_scan_interval);
+
+	return (OK);
+} /* hci_read_inquiry_scan_activity */
+
+/* Send Write_Inquiry_Scan_Activity command to the unit */
+static int
+hci_write_inquiry_scan_activity(int s, int argc, char **argv)
+{
+	ng_hci_write_inquiry_scan_activity_cp	cp;
+	ng_hci_write_inquiry_scan_activity_rp	rp;
+	int					n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 2:
+		/* inquiry scan interval */
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
+			return (USAGE);
+
+		cp.inquiry_scan_interval = (uint16_t) n;
+
+		/* inquiry scan window */
+		if (sscanf(argv[1], "%d", &n) != 1 || n < 0x12 || n > 0x1000)
+			return (USAGE);
+
+		cp.inquiry_scan_window = (uint16_t) n;
+
+		if (cp.inquiry_scan_window > cp.inquiry_scan_interval)
+			return (USAGE);
+
+		cp.inquiry_scan_interval = 
+			htole16(cp.inquiry_scan_interval);
+		cp.inquiry_scan_window = htole16(cp.inquiry_scan_window);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n",
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_inquiry_scan_activity */
+
+/* Send Read_Authentication_Enable command to the unit */
+static int
+hci_read_authentication_enable(int s, int argc, char **argv)
+{
+	ng_hci_read_auth_enable_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_AUTH_ENABLE),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n",
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Authentication Enable: %s [%d]\n",
+		rp.auth_enable? "Enabled" : "Disabled", rp.auth_enable);
+
+	return (OK);
+} /* hci_read_authentication_enable */
+
+/* Send Write_Authentication_Enable command to the unit */
+static int
+hci_write_authentication_enable(int s, int argc, char **argv)
+{
+	ng_hci_write_auth_enable_cp	cp;
+	ng_hci_write_auth_enable_rp	rp;
+	int				n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 1)
+			return (USAGE);
+
+		cp.auth_enable = (uint8_t) n;
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_AUTH_ENABLE),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_authentication_enable */
+
+/* Send Read_Encryption_Mode command to the unit */
+static int
+hci_read_encryption_mode(int s, int argc, char **argv)
+{
+	ng_hci_read_encryption_mode_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_ENCRYPTION_MODE),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Encryption mode: %s [%#02x]\n", 
+		hci_encrypt2str(rp.encryption_mode, 0), rp.encryption_mode);
+
+	return (OK);
+} /* hci_read_encryption_mode */
+
+/* Send Write_Encryption_Mode command to the unit */
+static int
+hci_write_encryption_mode(int s, int argc, char **argv)
+{
+	ng_hci_write_encryption_mode_cp	cp;
+	ng_hci_write_encryption_mode_rp	rp;
+	int				n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 2)
+			return (USAGE);
+
+		cp.encryption_mode = (uint8_t) n;
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_ENCRYPTION_MODE),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_encryption_mode */
+
+/* Send Read_Class_Of_Device command to the unit */
+static int
+hci_read_class_of_device(int s, int argc, char **argv)
+{
+	ng_hci_read_unit_class_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_UNIT_CLASS),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Class: %02x:%02x:%02x\n",
+		rp.uclass[2], rp.uclass[1], rp.uclass[0]);
+
+	return (0);
+} /* hci_read_class_of_device */
+
+/* Send Write_Class_Of_Device command to the unit */
+static int
+hci_write_class_of_device(int s, int argc, char **argv)
+{
+	ng_hci_write_unit_class_cp	cp;
+	ng_hci_write_unit_class_rp	rp;
+	int				n0, n1, n2;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%x:%x:%x", &n2, &n1, &n0) != 3)
+			return (USAGE);
+
+		cp.uclass[0] = (n0 & 0xff);
+		cp.uclass[1] = (n1 & 0xff);
+		cp.uclass[2] = (n2 & 0xff);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n0 = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_UNIT_CLASS),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n0) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_class_of_device */
+
+/* Send Read_Voice_Settings command to the unit */
+static int
+hci_read_voice_settings(int s, int argc, char **argv)
+{
+	ng_hci_read_voice_settings_rp	rp;
+	int				n,
+					input_coding,
+					input_data_format,
+					input_sample_size;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_VOICE_SETTINGS),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	rp.settings = le16toh(rp.settings);
+
+	input_coding      = (rp.settings & 0x0300) >> 8;
+	input_data_format = (rp.settings & 0x00c0) >> 6;
+	input_sample_size = (rp.settings & 0x0020) >> 5;
+
+	fprintf(stdout, "Voice settings: %#04x\n", rp.settings);
+	fprintf(stdout, "Input coding: %s [%d]\n",
+		hci_coding2str(input_coding), input_coding);
+	fprintf(stdout, "Input data format: %s [%d]\n",
+		hci_vdata2str(input_data_format), input_data_format);
+
+	if (input_coding == 0x00) /* Only for Linear PCM */
+		fprintf(stdout, "Input sample size: %d bit [%d]\n",
+			input_sample_size? 16 : 8, input_sample_size);
+
+	return (OK);
+} /* hci_read_voice_settings */
+
+/* Send Write_Voice_Settings command to the unit */
+static int
+hci_write_voice_settings(int s, int argc, char **argv)
+{
+	ng_hci_write_voice_settings_cp	cp;
+	ng_hci_write_voice_settings_rp	rp;
+	int				n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%x", &n) != 1)
+			return (USAGE);
+
+		cp.settings = (uint16_t) n;
+		cp.settings = htole16(cp.settings);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_VOICE_SETTINGS),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_voice_settings */
+
+/* Send Read_Number_Broadcast_Restransmissions */
+static int
+hci_read_number_broadcast_retransmissions(int s, int argc, char **argv)
+{
+	ng_hci_read_num_broadcast_retrans_rp	rp;
+	int					n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Number of broadcast retransmissions: %d\n",
+		rp.counter);
+
+	return (OK);
+} /* hci_read_number_broadcast_retransmissions */
+
+/* Send Write_Number_Broadcast_Restransmissions */
+static int
+hci_write_number_broadcast_retransmissions(int s, int argc, char **argv)
+{
+	ng_hci_write_num_broadcast_retrans_cp	cp;
+	ng_hci_write_num_broadcast_retrans_rp	rp;
+	int					n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0xff)
+			return (USAGE);
+
+		cp.counter = (uint8_t) n;
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_number_broadcast_retransmissions */
+
+/* Send Read_Hold_Mode_Activity command to the unit */
+static int
+hci_read_hold_mode_activity(int s, int argc, char **argv)
+{
+	ng_hci_read_hold_mode_activity_rp	rp;
+	int					n;
+	char					buffer[1024];
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Hold Mode Activities: %#02x\n", rp.hold_mode_activity);
+	if (rp.hold_mode_activity == 0)
+		fprintf(stdout, "Maintain current Power State");
+	else
+		fprintf(stdout, "%s", hci_hmode2str(rp.hold_mode_activity,
+				buffer, sizeof(buffer)));
+
+	fprintf(stdout, "\n");
+
+	return (OK);
+} /* hci_read_hold_mode_activity */
+
+/* Send Write_Hold_Mode_Activity command to the unit */
+static int
+hci_write_hold_mode_activity(int s, int argc, char **argv)
+{
+	ng_hci_write_hold_mode_activity_cp	cp;
+	ng_hci_write_hold_mode_activity_rp	rp;
+	int					n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 4)
+			return (USAGE);
+
+		cp.hold_mode_activity = (uint8_t) n;
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_hold_mode_activity */
+
+/* Send Read_SCO_Flow_Control_Enable command to the unit */
+static int
+hci_read_sco_flow_control_enable(int s, int argc, char **argv)
+{
+	ng_hci_read_sco_flow_control_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_SCO_FLOW_CONTROL),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "SCO flow control %s [%d]\n",
+		rp.flow_control? "enabled" : "disabled", rp.flow_control);
+
+	return (OK);
+} /* hci_read_sco_flow_control_enable */
+
+/* Send Write_SCO_Flow_Control_Enable command to the unit */
+static int
+hci_write_sco_flow_control_enable(int s, int argc, char **argv)
+{
+	ng_hci_write_sco_flow_control_cp	cp;
+	ng_hci_write_sco_flow_control_rp	rp;
+	int					n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 1)
+			return (USAGE);
+
+		cp.flow_control = (uint8_t) n;
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_sco_flow_control_enable */
+
+/* Send Read_Link_Supervision_Timeout command to the unit */
+static int
+hci_read_link_supervision_timeout(int s, int argc, char **argv)
+{
+	ng_hci_read_link_supervision_timo_cp	cp;
+	ng_hci_read_link_supervision_timo_rp	rp;
+	int					n;
+
+	switch (argc) {
+	case 1:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	rp.timeout = le16toh(rp.timeout);
+
+	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
+	fprintf(stdout, "Link supervision timeout: %.2f msec [%d slots]\n",
+		rp.timeout * 0.625, rp.timeout);
+
+	return (OK);
+} /* hci_read_link_supervision_timeout */
+
+/* Send Write_Link_Supervision_Timeout command to the unit */
+static int
+hci_write_link_supervision_timeout(int s, int argc, char **argv)
+{
+	ng_hci_write_link_supervision_timo_cp	cp;
+	ng_hci_write_link_supervision_timo_rp	rp;
+	int					n;
+
+	switch (argc) {
+	case 2:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+
+		/* link supervision timeout */
+		if (sscanf(argv[1], "%d", &n) != 1 || n < 0 || n > 0xffff)
+			return (USAGE);
+
+		cp.timeout = (uint16_t) (n & 0x0fff);
+		cp.timeout = htole16(cp.timeout);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_link_supervision_timeout */
+
+/* Send Read_Page_Scan_Period_Mode command to the unit */
+static int
+hci_read_page_scan_period_mode(int s, int argc, char **argv)
+{
+	ng_hci_read_page_scan_period_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_PAGE_SCAN_PERIOD),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Page scan period mode: %#02x\n",
+		rp.page_scan_period_mode);
+
+	return (OK);
+} /* hci_read_page_scan_period_mode */
+
+/* Send Write_Page_Scan_Period_Mode command to the unit */
+static int
+hci_write_page_scan_period_mode(int s, int argc, char **argv)
+{
+	ng_hci_write_page_scan_period_cp	cp;
+	ng_hci_write_page_scan_period_rp	rp;
+	int					n;
+
+	/* parse command arguments */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 2)
+			return (USAGE);
+	
+		cp.page_scan_period_mode = (n & 0xff);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_PAGE_SCAN_PERIOD),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_page_scan_period_mode */
+
+/* Send Read_Page_Scan_Mode command to the unit */
+static int
+hci_read_page_scan_mode(int s, int argc, char **argv)
+{
+	ng_hci_read_page_scan_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_READ_PAGE_SCAN),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Page scan mode: %#02x\n", rp.page_scan_mode);
+
+	return (OK);
+} /* hci_read_page_scan_mode */
+
+/* Send Write_Page_Scan_Mode command to the unit */
+static int
+hci_write_page_scan_mode(int s, int argc, char **argv)
+{
+	ng_hci_write_page_scan_cp	cp;
+	ng_hci_write_page_scan_rp	rp;
+	int				n;
+
+	/* parse command arguments */
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 3)
+			return (USAGE);
+	
+		cp.page_scan_mode = (n & 0xff);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND,
+			NG_HCI_OCF_WRITE_PAGE_SCAN),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_page_scan_mode */
+
+struct hci_command	host_controller_baseband_commands[] = {
+{
+"reset",
+"\nThe Reset command will reset the Host Controller and the Link Manager.\n" \
+"After the reset is completed, the current operational state will be lost,\n" \
+"the Bluetooth unit will enter standby mode and the Host Controller will\n" \
+"automatically revert to the default values for the parameters for which\n" \
+"default values are defined in the specification.",
+&hci_reset
+},
+{
+"read_pin_type",
+"\nThe Read_PIN_Type command is used for the Host to read whether the Link\n" \
+"Manager assumes that the Host supports variable PIN codes only a fixed PIN\n" \
+"code.",
+&hci_read_pin_type
+},
+{
+"write_pin_type <pin_type>",
+"\nThe Write_PIN_Type command is used for the Host to write to the Host\n" \
+"Controller whether the Host supports variable PIN codes or only a fixed PIN\n"\
+"code.\n\n" \
+"\t<pin_type> - dd; 0 - Variable; 1 - Fixed",
+&hci_write_pin_type
+},
+{
+"read_stored_link_key [<BD_ADDR>]",
+"\nThe Read_Stored_Link_Key command provides the ability to read one or\n" \
+"more link keys stored in the Bluetooth Host Controller. The Bluetooth Host\n" \
+"Controller can store a limited number of link keys for other Bluetooth\n" \
+"devices.\n\n" \
+"\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name",
+&hci_read_stored_link_key
+},
+{
+"write_stored_link_key <BD_ADDR> <key>",
+"\nThe Write_Stored_Link_Key command provides the ability to write one\n" \
+"or more link keys to be stored in the Bluetooth Host Controller. The\n" \
+"Bluetooth Host Controller can store a limited number of link keys for other\n"\
+"Bluetooth devices. If no additional space is available in the Bluetooth\n"\
+"Host Controller then no additional link keys will be stored.\n\n" \
+"\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \
+"\t<key>     - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx up to 16 bytes link key",
+&hci_write_stored_link_key
+},
+{
+"delete_stored_link_key [<BD_ADDR>]",
+"\nThe Delete_Stored_Link_Key command provides the ability to remove one\n" \
+"or more of the link keys stored in the Bluetooth Host Controller. The\n" \
+"Bluetooth Host Controller can store a limited number of link keys for other\n"\
+"Bluetooth devices.\n\n" \
+"\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name",
+&hci_delete_stored_link_key
+},
+{
+"change_local_name <name>",
+"\nThe Change_Local_Name command provides the ability to modify the user\n" \
+"friendly name for the Bluetooth unit.\n\n" \
+"\t<name> - string",
+&hci_change_local_name
+},
+{
+"read_local_name",
+"\nThe Read_Local_Name command provides the ability to read the\n" \
+"stored user-friendly name for the Bluetooth unit.",
+&hci_read_local_name
+},
+{
+"read_connection_accept_timeout",
+"\nThis command will read the value for the Connection_Accept_Timeout\n" \
+"configuration parameter. The Connection_Accept_Timeout configuration\n" \
+"parameter allows the Bluetooth hardware to automatically deny a\n" \
+"connection request after a specified time period has occurred and\n" \
+"the new connection is not accepted. Connection Accept Timeout\n" \
+"measured in Number of Baseband slots.",
+&hci_read_connection_accept_timeout
+},
+{
+"write_connection_accept_timeout <timeout>",
+"\nThis command will write the value for the Connection_Accept_Timeout\n" \
+"configuration parameter.\n\n" \
+"\t<timeout> - dddd; measured in number of baseband slots.",
+&hci_write_connection_accept_timeout
+},
+{
+"read_page_timeout",
+"\nThis command will read the value for the Page_Timeout configuration\n" \
+"parameter. The Page_Timeout configuration parameter defines the\n" \
+"maximum time the local Link Manager will wait for a baseband page\n" \
+"response from the remote unit at a locally initiated connection\n" \
+"attempt. Page Timeout measured in Number of Baseband slots.",
+&hci_read_page_timeout
+},
+{
+"write_page_timeout <timeout>",
+"\nThis command will write the value for the Page_Timeout configuration\n" \
+"parameter.\n\n" \
+"\t<timeout> - dddd; measured in number of baseband slots.",
+&hci_write_page_timeout
+},
+{
+"read_scan_enable",
+"\nThis command will read the value for the Scan_Enable parameter. The\n" \
+"Scan_Enable parameter controls whether or not the Bluetooth uint\n" \
+"will periodically scan for page attempts and/or inquiry requests\n" \
+"from other Bluetooth unit.\n\n" \
+"\t0x00 - No Scans enabled.\n" \
+"\t0x01 - Inquiry Scan enabled. Page Scan disabled.\n" \
+"\t0x02 - Inquiry Scan disabled. Page Scan enabled.\n" \
+"\t0x03 - Inquiry Scan enabled. Page Scan enabled.",
+&hci_read_scan_enable
+},
+{
+"write_scan_enable <scan_enable>",
+"\nThis command will write the value for the Scan_Enable parameter.\n" \
+"The Scan_Enable parameter controls whether or not the Bluetooth\n" \
+"unit will periodically scan for page attempts and/or inquiry\n" \
+"requests from other Bluetooth unit.\n\n" \
+"\t<scan_enable> - dd;\n" \
+"\t0 - No Scans enabled.\n" \
+"\t1 - Inquiry Scan enabled. Page Scan disabled.\n" \
+"\t2 - Inquiry Scan disabled. Page Scan enabled.\n" \
+"\t3 - Inquiry Scan enabled. Page Scan enabled.",
+&hci_write_scan_enable
+},
+{
+"read_page_scan_activity",
+"\nThis command will read the value for Page_Scan_Activity configuration\n" \
+"parameters. The Page_Scan_Interval configuration parameter defines the\n" \
+"amount of time between consecutive page scans. This time interval is \n" \
+"defined from when the Host Controller started its last page scan until\n" \
+"it begins the next page scan. The Page_Scan_Window configuration parameter\n" \
+"defines the amount of time for the duration of the page scan. The\n" \
+"Page_Scan_Window can only be less than or equal to the Page_Scan_Interval.",
+&hci_read_page_scan_activity
+},
+{
+"write_page_scan_activity interval(dddd) window(dddd)",
+"\nThis command will write the value for Page_Scan_Activity configuration\n" \
+"parameter. The Page_Scan_Interval configuration parameter defines the\n" \
+"amount of time between consecutive page scans. This is defined as the time\n" \
+"interval from when the Host Controller started its last page scan until it\n" \
+"begins the next page scan. The Page_Scan_Window configuration parameter\n" \
+"defines the amount of time for the duration of the page scan. \n" \
+"The Page_Scan_Window can only be less than or equal to the Page_Scan_Interval.\n\n" \
+"\t<interval> - Range: 0x0012 -- 0x100, Time = N * 0.625 msec\n" \
+"\t<window>   - Range: 0x0012 -- 0x100, Time = N * 0.625 msec",
+&hci_write_page_scan_activity
+},
+{
+"read_inquiry_scan_activity",
+"\nThis command will read the value for Inquiry_Scan_Activity configuration\n" \
+"parameter. The Inquiry_Scan_Interval configuration parameter defines the\n" \
+"amount of time between consecutive inquiry scans. This is defined as the\n" \
+"time interval from when the Host Controller started its last inquiry scan\n" \
+"until it begins the next inquiry scan.",
+&hci_read_inquiry_scan_activity
+},
+{
+"write_inquiry_scan_activity interval(dddd) window(dddd)",
+"\nThis command will write the value for Inquiry_Scan_Activity configuration\n"\
+"parameter. The Inquiry_Scan_Interval configuration parameter defines the\n" \
+"amount of time between consecutive inquiry scans. This is defined as the\n" \
+"time interval from when the Host Controller started its last inquiry scan\n" \
+"until it begins the next inquiry scan. The Inquiry_Scan_Window configuration\n" \
+"parameter defines the amount of time for the duration of the inquiry scan.\n" \
+"The Inquiry_Scan_Window can only be less than or equal to the Inquiry_Scan_Interval.\n\n" \
+"\t<interval> - Range: 0x0012 -- 0x100, Time = N * 0.625 msec\n" \
+"\t<window>   - Range: 0x0012 -- 0x100, Time = N * 0.625 msec",
+&hci_write_inquiry_scan_activity
+},
+{
+"read_authentication_enable",
+"\nThis command will read the value for the Authentication_Enable parameter.\n"\
+"The Authentication_Enable parameter controls if the local unit requires\n"\
+"to authenticate the remote unit at connection setup (between the\n" \
+"Create_Connection command or acceptance of an incoming ACL connection\n"\
+"and the corresponding Connection Complete event). At connection setup, only\n"\
+"the unit(s) with the Authentication_Enable parameter enabled will try to\n"\
+"authenticate the other unit.",
+&hci_read_authentication_enable
+},
+{
+"write_authentication_enable enable(0|1)",
+"\nThis command will write the value for the Authentication_Enable parameter.\n"\
+"The Authentication_Enable parameter controls if the local unit requires to\n"\
+"authenticate the remote unit at connection setup (between the\n" \
+"Create_Connection command or acceptance of an incoming ACL connection\n" \
+"and the corresponding Connection Complete event). At connection setup, only\n"\
+"the unit(s) with the Authentication_Enable parameter enabled will try to\n"\
+"authenticate the other unit.",
+&hci_write_authentication_enable
+},
+{
+"read_encryption_mode",
+"\nThis command will read the value for the Encryption_Mode parameter. The\n" \
+"Encryption_Mode parameter controls if the local unit requires encryption\n" \
+"to the remote unit at connection setup (between the Create_Connection\n" \
+"command or acceptance of an incoming ACL connection and the corresponding\n" \
+"Connection Complete event). At connection setup, only the unit(s) with\n" \
+"the Authentication_Enable parameter enabled and Encryption_Mode parameter\n" \
+"enabled will try to encrypt the connection to the other unit.\n\n" \
+"\t<encryption_mode>:\n" \
+"\t0x00 - Encryption disabled.\n" \
+"\t0x01 - Encryption only for point-to-point packets.\n" \
+"\t0x02 - Encryption for both point-to-point and broadcast packets.",
+&hci_read_encryption_mode
+},
+{
+"write_encryption_mode mode(0|1|2)",
+"\tThis command will write the value for the Encryption_Mode parameter.\n" \
+"The Encryption_Mode parameter controls if the local unit requires\n" \
+"encryption to the remote unit at connection setup (between the\n" \
+"Create_Connection command or acceptance of an incoming ACL connection\n" \
+"and the corresponding Connection Complete event). At connection setup,\n" \
+"only the unit(s) with the Authentication_Enable parameter enabled and\n" \
+"Encryption_Mode parameter enabled will try to encrypt the connection to\n" \
+"the other unit.\n\n" \
+"\t<encryption_mode> (dd)\n" \
+"\t0 - Encryption disabled.\n" \
+"\t1 - Encryption only for point-to-point packets.\n" \
+"\t2 - Encryption for both point-to-point and broadcast packets.",
+&hci_write_encryption_mode
+},
+{
+"read_class_of_device",
+"\nThis command will read the value for the Class_of_Device parameter.\n" \
+"The Class_of_Device parameter is used to indicate the capabilities of\n" \
+"the local unit to other units.",
+&hci_read_class_of_device
+},
+{
+"write_class_of_device class(xx:xx:xx)",
+"\nThis command will write the value for the Class_of_Device parameter.\n" \
+"The Class_of_Device parameter is used to indicate the capabilities of \n" \
+"the local unit to other units.\n\n" \
+"\t<class> (xx:xx:xx) - class of device",
+&hci_write_class_of_device
+},
+{
+"read_voice_settings",
+"\nThis command will read the values for the Voice_Setting parameter.\n" \
+"The Voice_Setting parameter controls all the various settings for voice\n" \
+"connections. These settings apply to all voice connections, and cannot be\n" \
+"set for individual voice connections. The Voice_Setting parameter controls\n" \
+"the configuration for voice connections: Input Coding, Air coding format,\n" \
+"input data format, Input sample size, and linear PCM parameter.",
+&hci_read_voice_settings
+},
+{
+"write_voice_settings settings(xxxx)",
+"\nThis command will write the values for the Voice_Setting parameter.\n" \
+"The Voice_Setting parameter controls all the various settings for voice\n" \
+"connections. These settings apply to all voice connections, and cannot be\n" \
+"set for individual voice connections. The Voice_Setting parameter controls\n" \
+"the configuration for voice connections: Input Coding, Air coding format,\n" \
+"input data format, Input sample size, and linear PCM parameter.\n\n" \
+"\t<voice_settings> (xxxx) - voice settings",
+&hci_write_voice_settings
+},
+{
+"read_number_broadcast_retransmissions",
+"\nThis command will read the unit's parameter value for the Number of\n" \
+"Broadcast Retransmissions. Broadcast packets are not acknowledged and are\n" \
+"unreliable.",
+&hci_read_number_broadcast_retransmissions
+},
+{
+"write_number_broadcast_retransmissions count(dd)",
+"\nThis command will write the unit's parameter value for the Number of\n" \
+"Broadcast Retransmissions. Broadcast packets are not acknowledged and are\n" \
+"unreliable.\n\n" \
+"\t<count> (dd) - number of broadcast retransimissions",
+&hci_write_number_broadcast_retransmissions
+},
+{
+"read_hold_mode_activity",
+"\nThis command will read the value for the Hold_Mode_Activity parameter.\n" \
+"The Hold_Mode_Activity value is used to determine what activities should\n" \
+"be suspended when the unit is in hold mode.",
+&hci_read_hold_mode_activity
+},
+{
+"write_hold_mode_activity settings(0|1|2|4)",
+"\nThis command will write the value for the Hold_Mode_Activity parameter.\n" \
+"The Hold_Mode_Activity value is used to determine what activities should\n" \
+"be suspended when the unit is in hold mode.\n\n" \
+"\t<settings> (dd) - bit mask:\n" \
+"\t0 - Maintain current Power State. Default\n" \
+"\t1 - Suspend Page Scan.\n" \
+"\t2 - Suspend Inquiry Scan.\n" \
+"\t4 - Suspend Periodic Inquiries.",
+&hci_write_hold_mode_activity
+},
+{
+"read_sco_flow_control_enable",
+"\nThe Read_SCO_Flow_Control_Enable command provides the ability to read\n" \
+"the SCO_Flow_Control_Enable setting. By using this setting, the Host can\n" \
+"decide if the Host Controller will send Number Of Completed Packets events\n" \
+"for SCO Connection Handles. This setting allows the Host to enable and\n" \
+"disable SCO flow control.",
+&hci_read_sco_flow_control_enable
+},
+{
+"write_sco_flow_control_enable enable(0|1)",
+"\nThe Write_SCO_Flow_Control_Enable command provides the ability to write\n" \
+"the SCO_Flow_Control_Enable setting. By using this setting, the Host can\n" \
+"decide if the Host Controller will send Number Of Completed Packets events\n" \
+"for SCO Connection Handles. This setting allows the Host to enable and\n" \
+"disable SCO flow control. The SCO_Flow_Control_Enable setting can only be\n" \
+"changed if no connections exist.",
+&hci_write_sco_flow_control_enable
+},
+{
+"read_link_supervision_timeout <connection_handle>",
+"\nThis command will read the value for the Link_Supervision_Timeout\n" \
+"parameter for the device. The Link_Supervision_Timeout parameter is used\n" \
+"by the master or slave Bluetooth device to monitor link loss. If, for any\n" \
+"reason, no Baseband packets are received from that Connection Handle for a\n" \
+"duration longer than the Link_Supervision_Timeout, the connection is\n"
+"disconnected.\n\n" \
+"\t<connection_handle> - dddd; connection handle\n",
+&hci_read_link_supervision_timeout
+},
+{
+"write_link_supervision_timeout <connection_handle> <timeout>",
+"\nThis command will write the value for the Link_Supervision_Timeout\n" \
+"parameter for the device. The Link_Supervision_Timeout parameter is used\n" \
+"by the master or slave Bluetooth device to monitor link loss. If, for any\n" \
+"reason, no Baseband packets are received from that connection handle for a\n" \
+"duration longer than the Link_Supervision_Timeout, the connection is\n" \
+"disconnected.\n\n" \
+"\t<connection_handle> - dddd; connection handle\n" \
+"\t<timeout>           - dddd; timeout measured in number of baseband slots\n",
+&hci_write_link_supervision_timeout
+},
+{
+"read_page_scan_period_mode",
+"\nThis command is used to read the mandatory Page_Scan_Period_Mode of the\n" \
+"local Bluetooth device. Every time an inquiry response message is sent, the\n"\
+"Bluetooth device will start a timer (T_mandatory_pscan), the value of which\n"\
+"is dependent on the Page_Scan_Period_Mode. As long as this timer has not\n" \
+"expired, the Bluetooth device will use the Page_Scan_Period_Mode for all\n" \
+"following page scans.",
+&hci_read_page_scan_period_mode
+},
+{
+"write_page_scan_period_mode <page_scan_period_mode>",
+"\nThis command is used to write the mandatory Page_Scan_Period_Mode of the\n" \
+"local Bluetooth device. Every time an inquiry response message is sent, the\n"\
+"Bluetooth device will start a timer (T_mandatory_pscan), the value of which\n"\
+"is dependent on the Page_Scan_Period_Mode. As long as this timer has not\n" \
+"expired, the Bluetooth device will use the Page_Scan_Period_Mode for all\n" \
+"following page scans.\n\n" \
+"\t<page_scan_period_mode> - dd; page scan period mode:\n" \
+"\t0x00 - P0 (Default)\n" \
+"\t0x01 - P1\n" \
+"\t0x02 - P2",
+&hci_write_page_scan_period_mode
+},
+{
+"read_page_scan_mode",
+"\nThis command is used to read the default page scan mode of the local\n" \
+"Bluetooth device. The Page_Scan_Mode parameter indicates the page scan mode\n"\
+"that is used for the default page scan. Currently one mandatory page scan\n"\
+"mode and three optional page scan modes are defined. Following an inquiry\n" \
+"response, if the Baseband timer T_mandatory_pscan has not expired, the\n" \
+"mandatory page scan mode must be applied.",
+&hci_read_page_scan_mode
+},
+{
+"write_page_scan_mode <page_scan_mode>",
+"\nThis command is used to write the default page scan mode of the local\n" \
+"Bluetooth device. The Page_Scan_Mode parameter indicates the page scan mode\n"\
+"that is used for the default page scan. Currently, one mandatory page scan\n"\
+"mode and three optional page scan modes are defined. Following an inquiry\n"\
+"response, if the Baseband timer T_mandatory_pscan has not expired, the\n" \
+"mandatory page scan mode must be applied.\n\n" \
+"\t<page_scan_mode> - dd; page scan mode:\n" \
+"\t0x00 - Mandatory Page Scan Mode (Default)\n" \
+"\t0x01 - Optional Page Scan Mode I\n" \
+"\t0x02 - Optional Page Scan Mode II\n" \
+"\t0x03 - Optional Page Scan Mode III",
+&hci_write_page_scan_mode
+},
+{ NULL, }
+};
+
diff --git a/usr.sbin/hccontrol/info.c b/usr.sbin/hccontrol/info.c
new file mode 100644
index 0000000000..420cce48e1
--- /dev/null
+++ b/usr.sbin/hccontrol/info.c
@@ -0,0 +1,216 @@
+/*
+ * info.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: info.c,v 1.3 2003/08/18 19:19:54 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/info.c 155964 2006-02-23 23:19:12Z markus $
+ */
+
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "hccontrol.h"
+
+/* Send Read_Local_Version_Information command to the unit */
+static int
+hci_read_local_version_information(int s, int argc, char **argv)
+{
+	ng_hci_read_local_ver_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
+			NG_HCI_OCF_READ_LOCAL_VER), (char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	rp.manufacturer = le16toh(rp.manufacturer);
+
+	fprintf(stdout, "HCI version: %s [%#02x]\n",
+		hci_ver2str(rp.hci_version), rp.hci_version);
+	fprintf(stdout, "HCI revision: %#04x\n",
+		le16toh(rp.hci_revision));
+	fprintf(stdout, "LMP version: %s [%#02x]\n",
+		hci_lmpver2str(rp.lmp_version), rp.lmp_version);
+	fprintf(stdout, "LMP sub-version: %#04x\n", 
+		le16toh(rp.lmp_subversion));
+	fprintf(stdout, "Manufacturer: %s [%#04x]\n", 
+		hci_manufacturer2str(rp.manufacturer), rp.manufacturer);
+
+	return (OK);
+} /* hci_read_local_version_information */
+
+/* Send Read_Local_Supported_Features command to the unit */
+static int
+hci_read_local_supported_features(int s, int argc, char **argv)
+{
+	ng_hci_read_local_features_rp	rp;
+	int				n;
+	char				buffer[1024];
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
+			NG_HCI_OCF_READ_LOCAL_FEATURES),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Features: ");
+	for (n = 0; n < sizeof(rp.features); n++)
+		fprintf(stdout, "%#02x ", rp.features[n]);
+	fprintf(stdout, "\n%s\n", hci_features2str(rp.features, 
+		buffer, sizeof(buffer)));
+
+	return (OK);
+} /* hci_read_local_supported_features */
+
+/* Sent Read_Buffer_Size command to the unit */
+static int
+hci_read_buffer_size(int s, int argc, char **argv)
+{
+	ng_hci_read_buffer_size_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
+			NG_HCI_OCF_READ_BUFFER_SIZE),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Max. ACL packet size: %d bytes\n",
+		le16toh(rp.max_acl_size));
+	fprintf(stdout, "Number of ACL packets: %d\n",
+		le16toh(rp.num_acl_pkt));
+	fprintf(stdout, "Max. SCO packet size: %d bytes\n",
+		rp.max_sco_size);
+	fprintf(stdout, "Number of SCO packets: %d\n",
+		le16toh(rp.num_sco_pkt));
+	
+	return (OK);
+} /* hci_read_buffer_size */
+
+/* Send Read_Country_Code command to the unit */
+static int
+hci_read_country_code(int s, int argc, char **argv)
+{
+	ng_hci_read_country_code_rp	rp;
+	int				n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
+			NG_HCI_OCF_READ_COUNTRY_CODE),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Country code: %s [%#02x]\n",
+			hci_cc2str(rp.country_code), rp.country_code);
+
+	return (OK);
+} /* hci_read_country_code */
+
+/* Send Read_BD_ADDR command to the unit */
+static int
+hci_read_bd_addr(int s, int argc, char **argv)
+{
+	ng_hci_read_bdaddr_rp	rp;
+	int			n;
+
+	n = sizeof(rp);
+	if (hci_simple_request(s, NG_HCI_OPCODE(NG_HCI_OGF_INFO,
+			NG_HCI_OCF_READ_BDADDR), (char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "BD_ADDR: %s\n", bt_ntoa(&rp.bdaddr, NULL));
+
+	return (OK);
+} /* hci_read_bd_addr */
+
+struct hci_command	info_commands[] = {
+{
+"read_local_version_information",
+"\nThis command will read the values for the version information for the\n" \
+"local Bluetooth unit.",
+&hci_read_local_version_information	
+},
+{
+"read_local_supported_features",
+"\nThis command requests a list of the supported features for the local\n" \
+"unit. This command will return a list of the LMP features.",
+&hci_read_local_supported_features
+},
+{
+"read_buffer_size",
+"\nThe Read_Buffer_Size command is used to read the maximum size of the\n" \
+"data portion of HCI ACL and SCO Data Packets sent from the Host to the\n" \
+"Host Controller.",
+&hci_read_buffer_size
+},
+{
+"read_country_code",
+"\nThis command will read the value for the Country_Code return parameter.\n" \
+"The Country_Code defines which range of frequency band of the ISM 2.4 GHz\n" \
+"band will be used by the unit.",
+&hci_read_country_code
+},
+{
+"read_bd_addr",
+"\nThis command will read the value for the BD_ADDR parameter. The BD_ADDR\n" \
+"is a 48-bit unique identifier for a Bluetooth unit.",
+&hci_read_bd_addr
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/hccontrol/link_control.c b/usr.sbin/hccontrol/link_control.c
new file mode 100644
index 0000000000..33da8cecf3
--- /dev/null
+++ b/usr.sbin/hccontrol/link_control.c
@@ -0,0 +1,960 @@
+/*
+ * link_control.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: link_control.c,v 1.4 2003/08/18 19:19:54 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/link_control.c 250460 2013-05-10 16:41:26Z eadler $
+ */
+
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "hccontrol.h"
+
+static void hci_inquiry_response (int n, uint8_t **b);
+
+/* Send Inquiry command to the unit */
+static int
+hci_inquiry(int s, int argc, char **argv)
+{
+	int			 n0, n1, n2, timo;
+	char			 b[512];
+	ng_hci_inquiry_cp	 cp;
+	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b;
+
+	/* set defaults */
+	cp.lap[2] = 0x9e;
+	cp.lap[1] = 0x8b;
+	cp.lap[0] = 0x33;
+	cp.inquiry_length = 5;
+	cp.num_responses = 8;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 3:
+		/* number of responses, range 0x00 - 0xff */
+		if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 0xff)
+			return (USAGE);
+
+		cp.num_responses = (n0 & 0xff);
+
+	case 2:
+		/* inquiry length (N * 1.28) sec, range 0x01 - 0x30 */
+		if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x1 || n0 > 0x30)
+			return (USAGE);
+
+		cp.inquiry_length = (n0 & 0xff);
+
+	case 1:
+		/* LAP */
+		if (sscanf(argv[0], "%x:%x:%x", &n2, &n1, &n0) != 3)
+			return (USAGE);
+
+		cp.lap[0] = (n0 & 0xff);
+		cp.lap[1] = (n1 & 0xff);
+		cp.lap[2] = (n2 & 0xff);
+
+	case 0:
+		/* use defaults */
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request and expect status back */
+	n0 = sizeof(b);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+			NG_HCI_OCF_INQUIRY), (char const *) &cp, sizeof(cp),
+			b, &n0) == ERROR)
+		return (ERROR);
+
+	if (*b != 0x00)
+		return (FAILED);
+
+	timo = timeout;
+	timeout = cp.inquiry_length * 1.28 + 1;
+
+wait_for_more:
+	/* wait for inquiry events */
+	n0 = sizeof(b);
+	if (hci_recv(s, b, &n0) == ERROR) {
+		timeout = timo;
+		return (ERROR);
+	}
+
+	if (n0 < sizeof(*e)) {
+		timeout = timo;
+		errno = EIO;
+		return (ERROR);
+	}
+
+	switch (e->event) {
+	case NG_HCI_EVENT_INQUIRY_RESULT: {
+		ng_hci_inquiry_result_ep	*ir = 
+				(ng_hci_inquiry_result_ep *)(e + 1);
+		uint8_t				*r = (uint8_t *)(ir + 1);
+
+		fprintf(stdout, "Inquiry result, num_responses=%d\n",
+			ir->num_responses);
+
+		for (n0 = 0; n0 < ir->num_responses; n0++)
+			hci_inquiry_response(n0, &r);
+
+		goto wait_for_more;
+		}
+
+	case NG_HCI_EVENT_INQUIRY_COMPL:
+		fprintf(stdout, "Inquiry complete. Status: %s [%#02x]\n",
+			hci_status2str(*(b + sizeof(*e))), *(b + sizeof(*e)));
+		break;
+
+	default:
+		goto wait_for_more;
+	}
+
+	timeout = timo;
+
+	return (OK);
+} /* hci_inquiry */
+
+/* Print Inquiry_Result event */
+static void
+hci_inquiry_response(int n, uint8_t **b)
+{
+	ng_hci_inquiry_response	*ir = (ng_hci_inquiry_response *)(*b);
+
+	fprintf(stdout, "Inquiry result #%d\n", n);
+	fprintf(stdout, "\tBD_ADDR: %s\n", hci_bdaddr2str(&ir->bdaddr));
+	fprintf(stdout, "\tPage Scan Rep. Mode: %#02x\n",
+		ir->page_scan_rep_mode);
+	fprintf(stdout, "\tPage Scan Period Mode: %#02x\n",
+		ir->page_scan_period_mode);
+	fprintf(stdout, "\tPage Scan Mode: %#02x\n",
+		ir->page_scan_mode);
+	fprintf(stdout, "\tClass: %02x:%02x:%02x\n",
+		ir->uclass[2], ir->uclass[1], ir->uclass[0]);
+	fprintf(stdout, "\tClock offset: %#04x\n",
+		le16toh(ir->clock_offset));
+
+	*b += sizeof(*ir);
+} /* hci_inquiry_response */
+
+/* Send Create_Connection command to the unit */
+static int
+hci_create_connection(int s, int argc, char **argv)
+{
+	int			 n0;
+	char			 b[512];
+	ng_hci_create_con_cp	 cp;
+	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b; 
+
+	/* Set defaults */
+	memset(&cp, 0, sizeof(cp));
+	cp.pkt_type = htole16(	NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |
+				NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |
+				NG_HCI_PKT_DM5);
+	cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;
+	cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;
+	cp.clock_offset = 0;
+	cp.accept_role_switch = 1;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 6:
+		/* accept role switch */
+		if (sscanf(argv[5], "%d", &n0) != 1)
+			return (USAGE);
+
+		cp.accept_role_switch = n0 ? 1 : 0;
+
+	case 5:
+		/* clock offset */
+		if (sscanf(argv[4], "%d", &n0) != 1)
+			return (USAGE);
+
+		cp.clock_offset = (n0 & 0xffff);
+		cp.clock_offset = htole16(cp.clock_offset);
+
+	case 4:
+		/* page scan mode */
+		if (sscanf(argv[3], "%d", &n0) != 1 || n0 < 0 || n0 > 3)
+			return (USAGE);
+
+		cp.page_scan_mode = (n0 & 0xff);
+
+	case 3:
+		/* page scan rep mode */
+		if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 2)
+			return (USAGE);
+
+		cp.page_scan_rep_mode = (n0 & 0xff);
+
+	case 2:
+		/* packet type */
+		if (sscanf(argv[1], "%x", &n0) != 1)
+			return (USAGE);
+
+		n0 &= (	NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 |
+			NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 |
+			NG_HCI_PKT_DM5);
+		if (n0 == 0)
+			return (USAGE);
+
+		cp.pkt_type = (n0 & 0xffff);
+		cp.pkt_type = htole16(cp.pkt_type);
+
+	case 1:
+		/* BD_ADDR */
+		if (!bt_aton(argv[0], &cp.bdaddr)) {
+			struct hostent	*he = NULL;
+
+			if ((he = bt_gethostbyname(argv[0])) == NULL)
+				return (USAGE);
+
+			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
+		}
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request and expect status response */
+	n0 = sizeof(b);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+			NG_HCI_OCF_CREATE_CON),
+			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
+		return (ERROR);
+
+	if (*b != 0x00)
+		return (FAILED);
+
+	/* wait for event */
+again:
+	n0 = sizeof(b);
+	if (hci_recv(s, b, &n0) == ERROR)
+		return (ERROR);
+	if (n0 < sizeof(*e)) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	if (e->event == NG_HCI_EVENT_CON_COMPL) {
+		ng_hci_con_compl_ep	*ep = (ng_hci_con_compl_ep *)(e + 1);
+
+		if (ep->status != 0x00) {
+			fprintf(stdout, "Status: %s [%#02x]\n", 
+				hci_status2str(ep->status), ep->status);
+			return (FAILED);
+		}
+
+		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
+		fprintf(stdout, "Connection handle: %d\n",
+			le16toh(ep->con_handle));
+		fprintf(stdout, "Encryption mode: %s [%d]\n",
+			hci_encrypt2str(ep->encryption_mode, 0),
+			ep->encryption_mode);
+	} else
+		goto again;
+
+	return (OK);
+} /* hci_create_connection */
+
+/* Send Disconnect command to the unit */
+static int
+hci_disconnect(int s, int argc, char **argv)
+{
+	int			 n;
+	char			 b[512];
+	ng_hci_discon_cp	 cp;
+	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b; 
+
+	/* Set defaults */
+	memset(&cp, 0, sizeof(cp));
+	cp.reason = 0x13;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 2:
+		/* reason */
+		if (sscanf(argv[1], "%d", &n) != 1 || n <= 0x00 || n > 0xff)
+			return (USAGE);
+
+		cp.reason = (uint8_t) (n & 0xff);
+
+	case 1:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request and expect status response */
+	n = sizeof(b);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+			NG_HCI_OCF_DISCON),
+			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
+		return (ERROR);
+
+	if (*b != 0x00)
+		return (FAILED);
+
+	/* wait for event */
+again:
+	n = sizeof(b);
+	if (hci_recv(s, b, &n) == ERROR)
+		return (ERROR);
+	if (n < sizeof(*e)) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	if (e->event == NG_HCI_EVENT_DISCON_COMPL) {
+		ng_hci_discon_compl_ep	*ep = (ng_hci_discon_compl_ep *)(e + 1);
+
+		if (ep->status != 0x00) {
+			fprintf(stdout, "Status: %s [%#02x]\n", 
+				hci_status2str(ep->status), ep->status);
+			return (FAILED);
+		}
+
+		fprintf(stdout, "Connection handle: %d\n",
+			le16toh(ep->con_handle));
+		fprintf(stdout, "Reason: %s [%#02x]\n",
+			hci_status2str(ep->reason), ep->reason);
+	} else
+		goto again;
+
+	return (OK);
+} /* hci_disconnect */
+
+/* Send Add_SCO_Connection command to the unit */
+static int
+hci_add_sco_connection(int s, int argc, char **argv)
+{
+	int			 n;
+	char			 b[512];
+	ng_hci_add_sco_con_cp	 cp;
+	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b; 
+
+	/* Set defaults */
+	memset(&cp, 0, sizeof(cp));
+	cp.pkt_type = htole16(NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3);
+
+	/* parse command parameters */
+	switch (argc) {
+	case 2:
+		/* packet type */
+		if (sscanf(argv[1], "%x", &n) != 1)
+			return (USAGE);
+
+		n &= (NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3);
+		if (n == 0)
+			return (USAGE);
+
+		cp.pkt_type = (uint16_t) (n & 0x0fff);
+		cp.pkt_type = htole16(cp.pkt_type);
+
+	case 1:
+		/* acl connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request and expect status response */
+	n = sizeof(b);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+			NG_HCI_OCF_ADD_SCO_CON),
+			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
+		return (ERROR);
+
+	if (*b != 0x00)
+		return (FAILED);
+
+	/* wait for event */
+again:
+	n = sizeof(b);
+	if (hci_recv(s, b, &n) == ERROR)
+		return (ERROR);
+	if (n < sizeof(*e)) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	if (e->event == NG_HCI_EVENT_CON_COMPL) {
+		ng_hci_con_compl_ep	*ep = (ng_hci_con_compl_ep *)(e + 1);
+
+		if (ep->status != 0x00) {
+			fprintf(stdout, "Status: %s [%#02x]\n", 
+				hci_status2str(ep->status), ep->status);
+			return (FAILED);
+		}
+
+		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
+		fprintf(stdout, "Connection handle: %d\n",
+			le16toh(ep->con_handle));
+		fprintf(stdout, "Encryption mode: %s [%d]\n",
+			hci_encrypt2str(ep->encryption_mode, 0),
+			ep->encryption_mode);
+	} else
+		goto again;
+
+	return (OK);
+} /* Add_SCO_Connection */
+
+/* Send Change_Connection_Packet_Type command to the unit */
+static int
+hci_change_connection_packet_type(int s, int argc, char **argv)
+{
+	int				 n;
+	char				 b[512];
+	ng_hci_change_con_pkt_type_cp	 cp;
+	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b; 
+
+	switch (argc) {
+	case 2:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+
+		/* packet type */
+		if (sscanf(argv[1], "%x", &n) != 1)
+			return (USAGE);
+
+		cp.pkt_type = (uint16_t) (n & 0xffff);
+		cp.pkt_type = htole16(cp.pkt_type);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request and expect status response */
+	n = sizeof(b);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+			NG_HCI_OCF_CHANGE_CON_PKT_TYPE),
+			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
+		return (ERROR);
+
+	if (*b != 0x00)
+		return (FAILED);
+
+	/* wait for event */
+again:
+	n = sizeof(b);
+	if (hci_recv(s, b, &n) == ERROR)
+		return (ERROR);
+	if (n < sizeof(*e)) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	if (e->event == NG_HCI_EVENT_CON_PKT_TYPE_CHANGED) {
+		ng_hci_con_pkt_type_changed_ep	*ep = 
+				(ng_hci_con_pkt_type_changed_ep *)(e + 1);
+
+		if (ep->status != 0x00) {
+			fprintf(stdout, "Status: %s [%#02x]\n", 
+				hci_status2str(ep->status), ep->status);
+			return (FAILED);
+		}
+
+		fprintf(stdout, "Connection handle: %d\n",
+			le16toh(ep->con_handle));
+		fprintf(stdout, "Packet type: %#04x\n",
+			le16toh(ep->pkt_type));
+	} else
+		goto again;
+
+	return (OK);
+} /* hci_change_connection_packet_type */
+
+/* Send Remote_Name_Request command to the unit */
+static int
+hci_remote_name_request(int s, int argc, char **argv)
+{
+	int				 n0;
+	char				 b[512];
+	ng_hci_remote_name_req_cp	 cp;
+	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b; 
+
+	memset(&cp, 0, sizeof(cp));
+	cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0;
+	cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 4:
+		/* clock_offset */
+		if (sscanf(argv[3], "%x", &n0) != 1)
+			return (USAGE);
+
+		cp.clock_offset = (n0 & 0xffff);
+		cp.clock_offset = htole16(cp.clock_offset);
+
+	case 3:
+		/* page_scan_mode */
+		if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x03)
+			return (USAGE);
+
+		cp.page_scan_mode = (n0 & 0xff);
+
+	case 2:
+		/* page_scan_rep_mode */
+		if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x02)
+			return (USAGE);
+
+		cp.page_scan_rep_mode = (n0 & 0xff);
+
+	case 1:
+		/* BD_ADDR */
+		if (!bt_aton(argv[0], &cp.bdaddr)) {
+			struct hostent	*he = NULL;
+
+			if ((he = bt_gethostbyname(argv[0])) == NULL)
+				return (USAGE);
+
+			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
+		}
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request and expect status response */
+	n0 = sizeof(b);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+			NG_HCI_OCF_REMOTE_NAME_REQ),
+			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
+		return (ERROR);
+
+	if (*b != 0x00)
+		return (FAILED);
+
+	/* wait for event */
+again:
+	n0 = sizeof(b);
+	if (hci_recv(s, b, &n0) == ERROR)
+		return (ERROR);
+	if (n0 < sizeof(*e)) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	if (e->event == NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL) {
+		ng_hci_remote_name_req_compl_ep	*ep = 
+				(ng_hci_remote_name_req_compl_ep *)(e + 1);
+
+		if (ep->status != 0x00) {
+			fprintf(stdout, "Status: %s [%#02x]\n", 
+				hci_status2str(ep->status), ep->status);
+			return (FAILED);
+		}
+
+		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
+		fprintf(stdout, "Name: %s\n", ep->name);
+	} else 
+		goto again;
+
+	return (OK);
+} /* hci_remote_name_request */
+
+/* Send Read_Remote_Supported_Features command to the unit */
+static int
+hci_read_remote_supported_features(int s, int argc, char **argv)
+{
+	int				 n;
+	char				 b[512];
+	ng_hci_read_remote_features_cp	 cp;
+	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b; 
+	char				 buffer[1024];
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		/* connecton handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request and expect status response */
+	n = sizeof(b);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+			NG_HCI_OCF_READ_REMOTE_FEATURES), 
+			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
+		return (ERROR);
+
+	if (*b != 0x00)
+		return (FAILED);
+
+	/* wait for event */
+again:
+	n = sizeof(b);
+	if (hci_recv(s, b, &n) == ERROR)
+		return (ERROR);
+
+	if (n < sizeof(*e)) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	if (e->event == NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL) {
+		ng_hci_read_remote_features_compl_ep	*ep = 
+				(ng_hci_read_remote_features_compl_ep *)(e + 1);
+
+		if (ep->status != 0x00) {
+			fprintf(stdout, "Status: %s [%#02x]\n", 
+				hci_status2str(ep->status), ep->status);
+			return (FAILED);
+		}
+
+		fprintf(stdout, "Connection handle: %d\n",
+			le16toh(ep->con_handle));
+		fprintf(stdout, "Features: ");
+		for (n = 0; n < sizeof(ep->features); n++)
+			fprintf(stdout, "%#02x ", ep->features[n]);
+		fprintf(stdout, "\n%s\n", hci_features2str(ep->features, 
+			buffer, sizeof(buffer)));
+	} else
+		goto again;
+
+	return (OK);
+} /* hci_read_remote_supported_features */
+
+/* Send Read_Remote_Version_Information command to the unit */
+static int
+hci_read_remote_version_information(int s, int argc, char **argv)
+{
+	int				 n;
+	char				 b[512];
+	ng_hci_read_remote_ver_info_cp	 cp;
+	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b; 
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		/* connecton handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request and expect status response */
+	n = sizeof(b);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+			NG_HCI_OCF_READ_REMOTE_VER_INFO), 
+			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
+		return (ERROR);
+
+	if (*b != 0x00)
+		return (FAILED);
+
+	/* wait for event */
+again:
+	n = sizeof(b);
+	if (hci_recv(s, b, &n) == ERROR)
+		return (ERROR);
+
+	if (n < sizeof(*e)) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	if (e->event == NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL) {
+		ng_hci_read_remote_ver_info_compl_ep	*ep = 
+				(ng_hci_read_remote_ver_info_compl_ep *)(e + 1);
+
+		if (ep->status != 0x00) {
+			fprintf(stdout, "Status: %s [%#02x]\n", 
+				hci_status2str(ep->status), ep->status);
+			return (FAILED);
+		}
+
+		ep->manufacturer = le16toh(ep->manufacturer);
+
+		fprintf(stdout, "Connection handle: %d\n",
+			le16toh(ep->con_handle));
+		fprintf(stdout, "LMP version: %s [%#02x]\n",
+			hci_lmpver2str(ep->lmp_version), ep->lmp_version);
+		fprintf(stdout, "LMP sub-version: %#04x\n",
+			le16toh(ep->lmp_subversion));
+		fprintf(stdout, "Manufacturer: %s [%#04x]\n",
+			hci_manufacturer2str(ep->manufacturer),
+			ep->manufacturer);
+	} else
+		goto again;
+
+	return (OK);
+} /* hci_read_remote_version_information */
+
+/* Send Read_Clock_Offset command to the unit */
+static int
+hci_read_clock_offset(int s, int argc, char **argv)
+{
+	int				 n;
+	char				 b[512];
+	ng_hci_read_clock_offset_cp	 cp;
+	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) b; 
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		/* connecton handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request and expect status response */
+	n = sizeof(b);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+			NG_HCI_OCF_READ_CLOCK_OFFSET),
+			(char const *) &cp, sizeof(cp), b, &n) == ERROR)
+		return (ERROR);
+
+	if (*b != 0x00)
+		return (FAILED);
+
+	/* wait for event */
+again:
+	n = sizeof(b);
+	if (hci_recv(s, b, &n) == ERROR)
+		return (ERROR);
+
+	if (n < sizeof(*e)) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	if (e->event == NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL) {
+		ng_hci_read_clock_offset_compl_ep	*ep = 
+				(ng_hci_read_clock_offset_compl_ep *)(e + 1);
+
+		if (ep->status != 0x00) {
+			fprintf(stdout, "Status: %s [%#02x]\n", 
+				hci_status2str(ep->status), ep->status);
+			return (FAILED);
+		}
+
+		fprintf(stdout, "Connection handle: %d\n",
+			le16toh(ep->con_handle));
+		fprintf(stdout, "Clock offset: %#04x\n",
+			le16toh(ep->clock_offset));
+	} else
+		goto again;
+
+	return (OK);
+} /* hci_read_clock_offset */
+
+struct hci_command	link_control_commands[] = {
+{
+"inquiry <LAP> <inquiry_length> <num_reponses>",
+"\nThis command will cause the Bluetooth unit to enter Inquiry Mode.\n" \
+"Inquiry Mode is used to discover other nearby Bluetooth units. The LAP\n" \
+"input parameter contains the LAP from which the inquiry access code shall\n" \
+"be derived when the inquiry procedure is made. The Inquiry_Length parameter\n"\
+"specifies the total duration of the Inquiry Mode and, when this time\n" \
+"expires, Inquiry will be halted. The Num_Responses parameter specifies the\n" \
+"number of responses that can be received before the Inquiry is halted.\n\n" \
+"\t<LAP>            - xx:xx:xx; 9e:8b:33 (GIAC), 93:8b:00 (LDIAC)\n" \
+"\t<inquiry_length> - dd; total length == dd * 1.28 sec\n" \
+"\t<num_responses>  - dd",
+&hci_inquiry
+},
+{
+"create_connection <BD_ADDR> <pkt> <rep_mode> <ps_mode> <clck_off> <role_sw>",
+"" \
+"\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n\n" \
+"\t<pkt>     - xxxx; packet type\n" \
+"" \
+"\t\tACL packets\n" \
+"\t\t-----------\n" \
+"\t\t0x0008 DM1\n" \
+"\t\t0x0010 DH1\n" \
+"\t\t0x0400 DM3\n" \
+"\t\t0x0800 DH3\n" \
+"\t\t0x4000 DM5\n" \
+"\t\t0x8000 DH5\n\n" \
+"" \
+"\trep_mode  - d; page scan repetition mode\n" \
+"" \
+"\t\tPage scan repetition modes\n" \
+"\t\t--------------------------\n" \
+"\t\t0 Page scan repetition mode 0\n" \
+"\t\t1 Page scan repetition mode 1\n" \
+"\t\t2 Page scan repetition mode 2\n" \
+"\n" \
+"\tps_mode   - d; Page scan mode\n" \
+"" \
+"\t\tPage scan modes\n" \
+"\t\t---------------\n" \
+"\t\t0 Mandatory page scan mode\n" \
+"\t\t1 Optional page scan mode1\n" \
+"\t\t2 Optional page scan mode2\n" \
+"\t\t3 Optional page scan mode3\n" \
+"\n" \
+"\tclck_off  - dddd; clock offset. Use 0 if unknown\n\n" \
+"\trole_sw   - d; allow (1) or deny role switch\n",
+&hci_create_connection
+},
+{
+"disconnect <connection_handle> <reason>",
+"\nThe Disconnection command is used to terminate an existing connection.\n" \
+"The connection handle command parameter indicates which connection is to\n" \
+"be disconnected. The Reason command parameter indicates the reason for\n" \
+"ending the connection.\n\n" \
+"\t<connection_handle> - dddd; connection handle\n" \
+"\t<reason>            - dd; reason; usually 19 (0x13) - user ended;\n" \
+"\t                      also 0x05, 0x13-0x15, 0x1A, 0x29",
+&hci_disconnect
+},
+{
+"add_sco_connection <acl connection handle> <packet type>",
+"This command will cause the link manager to create a SCO connection using\n" \
+"the ACL connection specified by the connection handle command parameter.\n" \
+"The Link Manager will determine how the new connection is established. This\n"\
+"connection is determined by the current state of the device, its piconet,\n" \
+"and the state of the device to be connected. The packet type command parameter\n" \
+"specifies which packet types the Link Manager should use for the connection.\n"\
+"The Link Manager must only use the packet type(s) specified by the packet\n" \
+"type command parameter for sending HCI SCO data packets. Multiple packet\n" \
+"types may be specified for the packet type command parameter by performing\n" \
+"a bitwise OR operation of the different packet types. Note: An SCO connection\n" \
+"can only be created when an ACL connection already exists and when it is\n" \
+"not put in park mode.\n\n" \
+"\t<connection_handle> - dddd; ACL connection handle\n" \
+"\t<packet_type>       - xxxx; packet type\n" \
+"" \
+"\t\tSCO packets\n" \
+"\t\t-----------\n" \
+"\t\t0x0020 HV1\n" \
+"\t\t0x0040 HV2\n" \
+"\t\t0x0080 HV3\n",
+&hci_add_sco_connection
+},
+{
+"change_connection_packet_type <connection_hande> <packet_type>",
+"The Change_Connection_Packet_Type command is used to change which packet\n" \
+"types can be used for a connection that is currently established. This\n" \
+"allows current connections to be dynamically modified to support different\n" \
+"types of user data. The Packet_Type command parameter specifies which\n" \
+"packet types the Link Manager can use for the connection. Multiple packet\n" \
+"types may be specified for the Packet_Type command parameter by bitwise OR\n" \
+"operation of the different packet types.\n\n" \
+"\t<connection_handle> - dddd; connection handle\n" \
+"\t<packet_type>       - xxxx; packet type mask\n" \
+"" \
+"\t\tACL packets\n" \
+"\t\t-----------\n" \
+"\t\t0x0008 DM1\n" \
+"\t\t0x0010 DH1\n" \
+"\t\t0x0400 DM3\n" \
+"\t\t0x0800 DH3\n" \
+"\t\t0x4000 DM5\n" \
+"\t\t0x8000 DH5\n\n" \
+"" \
+"\t\tSCO packets\n" \
+"\t\t-----------\n" \
+"\t\t0x0020 HV1\n" \
+"\t\t0x0040 HV2\n" \
+"\t\t0x0080 HV3\n" \
+"",
+&hci_change_connection_packet_type
+},
+{
+"remote_name_request <BD_ADDR> <ps_rep_mode> <ps_mode> <clock_offset>",
+"\nThe Remote_Name_Request command is used to obtain the user-friendly\n" \
+"name of another Bluetooth unit.\n\n" \
+"\t<BD_ADDR>      - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \
+"\t<ps_rep_mode>  - dd; page scan repetition mode [0-2]\n" \
+"\t<ps_mode>      - dd; page scan mode [0-3]\n" \
+"\t<clock_offset> - xxxx; clock offset [0 - 0xffff]",
+&hci_remote_name_request
+},
+{
+"read_remote_supported_features <connection_handle>",
+"\nThis command requests a list of the supported features for the remote\n" \
+"unit identified by the connection handle parameter. The connection handle\n" \
+"must be a connection handle for an ACL connection.\n\n" \
+"\t<connection_handle> - dddd; connection handle",
+&hci_read_remote_supported_features
+},
+{
+"read_remote_version_information <connection_handle>",
+"\nThis command will obtain the values for the version information for the\n" \
+"remote Bluetooth unit identified by the connection handle parameter. The\n" \
+"connection handle must be a connection handle for an ACL connection.\n\n" \
+"\t<connection_handle> - dddd; connection handle",
+&hci_read_remote_version_information
+},
+{
+"read_clock_offset <connection_handle>",
+"\nThis command allows the Host to read the clock offset from the remote unit.\n" \
+"\t<connection_handle> - dddd; connection handle",
+&hci_read_clock_offset
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/hccontrol/link_policy.c b/usr.sbin/hccontrol/link_policy.c
new file mode 100644
index 0000000000..7020b161e6
--- /dev/null
+++ b/usr.sbin/hccontrol/link_policy.c
@@ -0,0 +1,305 @@
+/*
+ * link_policy.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: link_policy.c,v 1.3 2003/08/18 19:19:54 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/link_policy.c 133178 2004-08-05 16:32:41Z emax $
+ */
+
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "hccontrol.h"
+
+/* Send Role Discovery to the unit */
+static int
+hci_role_discovery(int s, int argc, char **argv)
+{
+	ng_hci_role_discovery_cp	cp;
+	ng_hci_role_discovery_rp	rp;
+	int				n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
+			NG_HCI_OCF_ROLE_DISCOVERY), 
+			(char const *) &cp, sizeof(cp), 
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
+	fprintf(stdout, "Role: %s [%#x]\n",
+		(rp.role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", rp.role);
+
+	return (OK);
+} /* hci_role_discovery */
+
+/* Send Swith Role to the unit */
+static int
+hci_switch_role(int s, int argc, char **argv)
+{
+	int			 n0;
+	char			 b[512];
+	ng_hci_switch_role_cp	 cp;
+	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) b; 
+
+	/* parse command parameters */
+	switch (argc) {
+	case 2:
+		/* bdaddr */
+		if (!bt_aton(argv[0], &cp.bdaddr)) {
+			struct hostent	*he = NULL;
+
+			if ((he = bt_gethostbyname(argv[0])) == NULL)
+				return (USAGE);
+
+			memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr));
+		}
+
+		/* role */
+		if (sscanf(argv[1], "%d", &n0) != 1)
+			return (USAGE);
+
+		cp.role = n0? NG_HCI_ROLE_SLAVE : NG_HCI_ROLE_MASTER;
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request and expect status response */
+	n0 = sizeof(b);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
+			NG_HCI_OCF_SWITCH_ROLE),
+			(char const *) &cp, sizeof(cp), b, &n0) == ERROR)
+		return (ERROR);
+
+	if (*b != 0x00)
+		return (FAILED);
+
+	/* wait for event */
+again:
+	n0 = sizeof(b);
+	if (hci_recv(s, b, &n0) == ERROR)
+		return (ERROR);
+	if (n0 < sizeof(*e)) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	if (e->event == NG_HCI_EVENT_ROLE_CHANGE) {
+		ng_hci_role_change_ep	*ep = (ng_hci_role_change_ep *)(e + 1);
+
+		if (ep->status != 0x00) {
+			fprintf(stdout, "Status: %s [%#02x]\n", 
+				hci_status2str(ep->status), ep->status);
+			return (FAILED);
+		}
+
+		fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr));
+		fprintf(stdout, "Role: %s [%#x]\n",
+			(ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave",
+			ep->role);
+	} else
+		goto again;
+
+	return (OK);
+} /* hci_switch_role */
+
+/* Send Read_Link_Policy_Settings command to the unit */
+static int
+hci_read_link_policy_settings(int s, int argc, char **argv)
+{
+	ng_hci_read_link_policy_settings_cp	cp;
+	ng_hci_read_link_policy_settings_rp	rp;
+	int					n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 1:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
+			NG_HCI_OCF_READ_LINK_POLICY_SETTINGS), 
+			(char const *) &cp, sizeof(cp), 
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
+	fprintf(stdout, "Link policy settings: %#x\n", le16toh(rp.settings));
+
+	return (OK);
+} /* hci_read_link_policy_settings */
+
+/* Send Write_Link_Policy_Settings command to the unit */
+static int
+hci_write_link_policy_settings(int s, int argc, char **argv)
+{
+	ng_hci_write_link_policy_settings_cp	cp;
+	ng_hci_write_link_policy_settings_rp	rp;
+	int					n;
+
+	/* parse command parameters */
+	switch (argc) {
+	case 2:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+
+		/* link policy settings */
+		if (sscanf(argv[1], "%x", &n) != 1)
+			return (USAGE);
+
+		cp.settings = (uint16_t) (n & 0x0ffff);
+		cp.settings = htole16(cp.settings);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send request */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
+			NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS), 
+			(char const *) &cp, sizeof(cp), 
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	return (OK);
+} /* hci_write_link_policy_settings */
+
+struct hci_command	link_policy_commands[] = {
+{
+"role_discovery <connection_handle>",
+"\nThe Role_Discovery command is used for a Bluetooth device to determine\n" \
+"which role the device is performing for a particular Connection Handle.\n" \
+"The connection handle must be a connection handle for an ACL connection.\n\n" \
+"\t<connection_handle> - dddd; connection handle",
+&hci_role_discovery
+},
+{
+"switch_role <BD_ADDR> <role>",
+"\nThe Switch_Role command is used for a Bluetooth device to switch the\n" \
+"current role the device is performing for a particular connection with\n" \
+"another specified Bluetooth device. The BD_ADDR command parameter indicates\n"\
+"for which connection the role switch is to be performed. The Role indicates\n"\
+"the requested new role that the local device performs. Note: the BD_ADDR\n" \
+"command parameter must specify a Bluetooth device for which a connection\n"
+"already exists.\n\n" \
+"\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \
+"\t<role>    - dd; role; 0 - Master, 1 - Slave",
+&hci_switch_role
+},
+{
+"read_link_policy_settings <connection_handle>",
+"\nThis command will read the Link Policy setting for the specified connection\n"\
+"handle. The link policy settings parameter determines the behavior of the\n" \
+"local Link Manager when it receives a request from a remote device or it\n" \
+"determines itself to change the master-slave role or to enter the hold,\n" \
+"sniff, or park mode. The local Link Manager will automatically accept or\n" \
+"reject such a request from the remote device, and may even autonomously\n" \
+"request itself, depending on the value of the link policy settings parameter\n"\
+"for the corresponding connection handle. The connection handle must be a\n" \
+"connection handle for an ACL connection.\n\n" \
+"\t<connection_handle> - dddd; connection handle",
+&hci_read_link_policy_settings
+},
+{
+"write_link_policy_settings <connection_handle> <settings>",
+"\nThis command will write the Link Policy setting for the specified connection\n"\
+"handle. The link policy settings parameter determines the behavior of the\n" \
+"local Link Manager when it receives a request from a remote device or it\n" \
+"determines itself to change the master-slave role or to enter the hold,\n" \
+"sniff, or park mode. The local Link Manager will automatically accept or\n" \
+"reject such a request from the remote device, and may even autonomously\n" \
+"request itself, depending on the value of the link policy settings parameter\n"\
+"for the corresponding connection handle. The connection handle must be a\n" \
+"connection handle for an ACL connection. Multiple Link Manager policies may\n"\
+"be specified for the link policy settings parameter by performing a bitwise\n"\
+"OR operation of the different activity types.\n\n" \
+"\t<connection_handle> - dddd; connection handle\n" \
+"\t<settings>          - xxxx; settings\n" \
+"\t\t0x0000 - Disable All LM Modes (Default)\n" \
+"\t\t0x0001 - Enable Master Slave Switch\n" \
+"\t\t0x0002 - Enable Hold Mode\n" \
+"\t\t0x0004 - Enable Sniff Mode\n" \
+"\t\t0x0008 - Enable Park Mode\n",
+&hci_write_link_policy_settings
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/hccontrol/node.c b/usr.sbin/hccontrol/node.c
new file mode 100644
index 0000000000..1da3a13123
--- /dev/null
+++ b/usr.sbin/hccontrol/node.c
@@ -0,0 +1,607 @@
+/*
+ * node.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: node.c,v 1.6 2003/07/22 21:14:02 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/node.c 158834 2006-05-22 17:58:09Z markus $
+ */
+
+#include <sys/ioctl.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <netgraph7/ng_message.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "hccontrol.h"
+
+/* Send Read_Node_State command to the node */
+static int
+hci_read_node_state(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_state	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "State: %#x\n", r.state);
+
+	return (OK);
+} /* hci_read_node_state */
+
+/* Send Intitialize command to the node */
+static int
+hci_node_initialize(int s, int argc, char **argv)
+{
+	if (ioctl(s, SIOC_HCI_RAW_NODE_INIT) < 0)
+		return (ERROR);
+
+	return (OK);
+} /* hci_node_initialize */
+
+/* Send Read_Debug_Level command to the node */
+static int
+hci_read_debug_level(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_debug	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "Debug level: %d\n", r.debug);
+
+	return (OK);
+} /* hci_read_debug_level */
+
+/* Send Write_Debug_Level command to the node */
+static int
+hci_write_debug_level(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_debug	r;
+  
+	memset(&r, 0, sizeof(r));
+	switch (argc) {
+	case 1:
+		r.debug = atoi(argv[0]);
+		break;
+ 
+	default:
+		return (USAGE);
+	}
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_SET_DEBUG, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	return (OK);
+} /* hci_write_debug_level */
+
+/* Send Read_Node_Buffer_Size command to the node */
+static int
+hci_read_node_buffer_size(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_buffer	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "Number of free command buffers: %d\n",
+		r.buffer.cmd_free);
+	fprintf(stdout, "Max. ACL packet size: %d\n",
+		r.buffer.acl_size);
+	fprintf(stdout, "Numbef of free ACL buffers: %d\n",
+		r.buffer.acl_free);
+	fprintf(stdout, "Total number of ACL buffers: %d\n",
+		r.buffer.acl_pkts);
+	fprintf(stdout, "Max. SCO packet size: %d\n",
+		r.buffer.sco_size);
+	fprintf(stdout, "Numbef of free SCO buffers: %d\n",
+		r.buffer.sco_free);
+	fprintf(stdout, "Total number of SCO buffers: %d\n",
+		r.buffer.sco_pkts);
+
+	return (OK);
+} /* hci_read_node_buffer_size */
+
+/* Send Read_Node_BD_ADDR command to the node */
+static int
+hci_read_node_bd_addr(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_bdaddr	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "BD_ADDR: %s\n", bt_ntoa(&r.bdaddr, NULL));
+
+	return (OK);
+} /* hci_read_node_bd_addr */
+
+/* Send Read_Node_Features command to the node */
+static int
+hci_read_node_features(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_features	r;
+	int						n;
+	char						buffer[1024];
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "Features: ");
+	for (n = 0; n < sizeof(r.features)/sizeof(r.features[0]); n++)
+		fprintf(stdout, "%#02x ", r.features[n]);
+	fprintf(stdout, "\n%s\n", hci_features2str(r.features, 
+		buffer, sizeof(buffer)));
+
+	return (OK);
+} /* hci_read_node_features */
+
+/* Send Read_Node_Stat command to the node */
+static int
+hci_read_node_stat(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_stat	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "Commands sent: %d\n", r.stat.cmd_sent);
+	fprintf(stdout, "Events received: %d\n", r.stat.evnt_recv);
+	fprintf(stdout, "ACL packets received: %d\n", r.stat.acl_recv);
+	fprintf(stdout, "ACL packets sent: %d\n", r.stat.acl_sent);
+	fprintf(stdout, "SCO packets received: %d\n", r.stat.sco_recv);
+	fprintf(stdout, "SCO packets sent: %d\n", r.stat.sco_sent);
+	fprintf(stdout, "Bytes received: %d\n", r.stat.bytes_recv);
+	fprintf(stdout, "Bytes sent: %d\n", r.stat.bytes_sent);
+
+	return (OK);
+} /* hci_read_node_stat */
+
+/* Send Reset_Node_Stat command to the node */
+static int
+hci_reset_node_stat(int s, int argc, char **argv)
+{
+	if (ioctl(s, SIOC_HCI_RAW_NODE_RESET_STAT) < 0)
+		return (ERROR);
+
+	return (OK);
+} /* hci_reset_node_stat */
+
+/* Send Flush_Neighbor_Cache command to the node */
+static int
+hci_flush_neighbor_cache(int s, int argc, char **argv)
+{
+	if (ioctl(s, SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE) < 0)
+		return (ERROR);
+
+	return (OK);
+} /* hci_flush_neighbor_cache */
+
+/* Send Read_Neighbor_Cache command to the node */
+static int
+hci_read_neighbor_cache(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_neighbor_cache	r;
+	int						n, error = OK;
+
+	memset(&r, 0, sizeof(r));
+	r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM;
+	r.entries = calloc(NG_HCI_MAX_NEIGHBOR_NUM,
+				sizeof(ng_hci_node_neighbor_cache_entry_ep));
+	if (r.entries == NULL) {
+		errno = ENOMEM;
+		return (ERROR);
+	}
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE, &r,
+			sizeof(r)) < 0) {
+		error = ERROR;
+		goto out;
+	}
+
+	fprintf(stdout,
+"BD_ADDR           " \
+"Features                " \
+"Clock offset " \
+"Page scan " \
+"Rep. scan\n");
+
+	for (n = 0; n < r.num_entries; n++) {
+		fprintf(stdout, 
+"%-17.17s " \
+"%02x %02x %02x %02x %02x %02x %02x %02x " \
+"%#12x " \
+"%#9x " \
+"%#9x\n",
+			hci_bdaddr2str(&r.entries[n].bdaddr),
+			r.entries[n].features[0], r.entries[n].features[1],
+			r.entries[n].features[2], r.entries[n].features[3],
+			r.entries[n].features[4], r.entries[n].features[5],
+			r.entries[n].features[6], r.entries[n].features[7],
+			r.entries[n].clock_offset, r.entries[n].page_scan_mode,
+			r.entries[n].page_scan_rep_mode);
+	}
+out:
+	free(r.entries);
+
+	return (error);
+} /* hci_read_neightbor_cache */
+
+/* Send Read_Connection_List command to the node */
+static int
+hci_read_connection_list(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_con_list	r;
+	int					n, error = OK;
+
+	memset(&r, 0, sizeof(r));
+	r.num_connections = NG_HCI_MAX_CON_NUM;
+	r.connections = calloc(NG_HCI_MAX_CON_NUM, sizeof(ng_hci_node_con_ep));
+	if (r.connections == NULL) {
+		errno = ENOMEM;
+		return (ERROR);
+	}
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
+		error = ERROR;
+		goto out;
+	}
+
+	fprintf(stdout,
+"Remote BD_ADDR    " \
+"Handle " \
+"Type " \
+"Mode " \
+"Role " \
+"Encrypt " \
+"Pending " \
+"Queue " \
+"State\n");
+
+	for (n = 0; n < r.num_connections; n++) {
+		fprintf(stdout,
+"%-17.17s " \
+"%6d " \
+"%4.4s " \
+"%4d " \
+"%4.4s " \
+"%7.7s " \
+"%7d " \
+"%5d " \
+"%s\n",
+			hci_bdaddr2str(&r.connections[n].bdaddr),
+			r.connections[n].con_handle,
+			(r.connections[n].link_type == NG_HCI_LINK_ACL)?
+				"ACL" : "SCO",
+			r.connections[n].mode,
+			(r.connections[n].role == NG_HCI_ROLE_MASTER)?
+				"MAST" : "SLAV",
+			hci_encrypt2str(r.connections[n].encryption_mode, 1),
+			r.connections[n].pending,
+			r.connections[n].queue_len,
+			hci_con_state2str(r.connections[n].state));
+	}
+out:
+	free(r.connections);
+
+	return (error);
+} /* hci_read_connection_list */
+
+/* Send Read_Node_Link_Policy_Settings_Mask command to the node */
+int
+hci_read_node_link_policy_settings_mask(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_link_policy_mask	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "Link Policy Settings mask: %#04x\n", r.policy_mask);
+
+	return (OK);
+} /* hci_read_node_link_policy_settings_mask */
+
+/* Send Write_Node_Link_Policy_Settings_Mask command to the node */
+int
+hci_write_node_link_policy_settings_mask(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_link_policy_mask	r;
+	int							m;
+
+	memset(&r, 0, sizeof(r));
+
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%x", &m) != 1)
+			return (USAGE);
+
+		r.policy_mask = (m & 0xffff);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	return (OK);
+} /* hci_write_node_link_policy_settings_mask */
+
+/* Send Read_Node_Packet_Mask command to the node */
+int
+hci_read_node_packet_mask(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_packet_mask	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "Packet mask: %#04x\n", r.packet_mask);
+
+	return (OK);
+} /* hci_read_node_packet_mask */
+
+/* Send Write_Node_Packet_Mask command to the node */
+int
+hci_write_node_packet_mask(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_packet_mask	r;
+	int						m;
+
+	memset(&r, 0, sizeof(r));
+
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%x", &m) != 1)
+			return (USAGE);
+
+		r.packet_mask = (m & 0xffff);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_SET_PACKET_MASK, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	return (OK);
+} /* hci_write_node_packet_mask */
+
+/* Send Read_Node_Role_Switch command to the node */
+int
+hci_read_node_role_switch(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_role_switch	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "Role switch: %d\n", r.role_switch);
+
+	return (OK);
+} /* hci_read_node_role_switch */
+
+/* Send Write_Node_Role_Switch command to the node */
+int
+hci_write_node_role_switch(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_role_switch	r;
+	int						m;
+
+	memset(&r, 0, sizeof(r));
+
+	switch (argc) {
+	case 1:
+		if (sscanf(argv[0], "%d", &m) != 1)
+			return (USAGE);
+
+		r.role_switch = m? 1 : 0;
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	return (OK);
+} /* hci_write_node_role_switch */
+
+/* Send Read_Node_List command to the node */
+int
+hci_read_node_list(int s, int argc, char **argv)
+{
+	struct ng_btsocket_hci_raw_node_list_names	r;
+	int						i;
+
+	r.num_names = MAX_NODE_NUM;
+	r.names = (struct nodeinfo*)calloc(MAX_NODE_NUM, sizeof(struct nodeinfo));
+	if (r.names == NULL)
+		return (ERROR);
+
+	if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0) {
+		free(r.names);
+		return (ERROR);
+	}
+
+	fprintf(stdout, "Name            ID       Num hooks\n");
+	for (i = 0; i < r.num_names; ++i)
+		fprintf(stdout, "%-15s %08x %9d\n",
+		    r.names[i].name, r.names[i].id, r.names[i].hooks);
+
+	free(r.names);
+
+	return (OK);
+} /* hci_read_node_list */
+
+struct hci_command	node_commands[] = {
+{
+"read_node_state",
+"Get the HCI node state",
+&hci_read_node_state
+},
+{
+"initialize",
+"Initialize the HCI node",
+&hci_node_initialize
+},
+{
+"read_debug_level",
+"Read the HCI node debug level",
+&hci_read_debug_level
+},
+{
+"write_debug_level <level>",
+"Write the HCI node debug level",
+&hci_write_debug_level
+},
+{
+"read_node_buffer_size",
+"Read the HCI node buffer information. This will return current state of the\n"\
+"HCI buffer for the HCI node",
+&hci_read_node_buffer_size
+},
+{
+"read_node_bd_addr",
+"Read the HCI node BD_ADDR. Returns device BD_ADDR as cached by the HCI node",
+&hci_read_node_bd_addr
+},
+{
+"read_node_features",
+"Read the HCI node features. This will return list of supported features as\n" \
+"cached by the HCI node",
+&hci_read_node_features
+},
+{
+"read_node_stat",
+"Read packets and bytes counters for the HCI node",
+&hci_read_node_stat
+},
+{
+"reset_node_stat",
+"Reset packets and bytes counters for the HCI node",
+&hci_reset_node_stat
+},
+{
+"flush_neighbor_cache",
+"Flush content of the HCI node neighbor cache",
+&hci_flush_neighbor_cache
+},
+{
+"read_neighbor_cache",
+"Read content of the HCI node neighbor cache",
+&hci_read_neighbor_cache
+},
+{
+"read_connection_list",
+"Read the baseband connection descriptors list for the HCI node",
+&hci_read_connection_list
+},
+{
+"read_node_link_policy_settings_mask",
+"Read the value of the Link Policy Settinngs mask for the HCI node",
+&hci_read_node_link_policy_settings_mask
+},
+{
+"write_node_link_policy_settings_mask <policy_mask>",
+"Write the value of the Link Policy Settings mask for the HCI node. By default\n" \
+"all supported Link Policy modes (as reported by the local device features) are\n"\
+"enabled. The particular Link Policy mode is enabled if local device supports\n"\
+"it and correspinding bit in the mask was set\n\n" \
+"\t<policy_mask> - xxxx; Link Policy mask\n" \
+"\t\t0x0000 - Disable All LM Modes\n" \
+"\t\t0x0001 - Enable Master Slave Switch\n" \
+"\t\t0x0002 - Enable Hold Mode\n" \
+"\t\t0x0004 - Enable Sniff Mode\n" \
+"\t\t0x0008 - Enable Park Mode\n",
+&hci_write_node_link_policy_settings_mask
+},
+{
+"read_node_packet_mask",
+"Read the value of the Packet mask for the HCI node",
+&hci_read_node_packet_mask
+},
+{
+"write_node_packet_mask <packet_mask>",
+"Write the value of the Packet mask for the HCI node. By default all supported\n" \
+"packet types (as reported by the local device features) are enabled. The\n" \
+"particular packet type is enabled if local device supports it and corresponding\n" \
+"bit in the mask was set\n\n" \
+"\t<packet_mask> - xxxx; packet type mask\n" \
+"" \
+"\t\tACL packets\n" \
+"\t\t-----------\n" \
+"\t\t0x0008 DM1\n" \
+"\t\t0x0010 DH1\n" \
+"\t\t0x0400 DM3\n" \
+"\t\t0x0800 DH3\n" \
+"\t\t0x4000 DM5\n" \
+"\t\t0x8000 DH5\n" \
+"\n" \
+"\t\tSCO packets\n" \
+"\t\t-----------\n" \
+"\t\t0x0020 HV1\n" \
+"\t\t0x0040 HV2\n" \
+"\t\t0x0080 HV3\n",
+&hci_write_node_packet_mask
+},
+{
+"read_node_role_switch",
+"Read the value of the Role Switch parameter for the HCI node",
+&hci_read_node_role_switch
+},
+{
+"write_node_role_switch {0|1}",
+"Write the value of the Role Switch parameter for the HCI node. By default,\n" \
+"if Role Switch is supported, local device will try to perform Role Switch\n" \
+"and become Master on incoming connection. Some devices do not support Role\n" \
+"Switch and thus incomming connections from such devices will fail. Setting\n" \
+"this parameter to zero will prevent Role Switch and thus accepting device\n" \
+"will remain Slave",
+&hci_write_node_role_switch
+},
+{
+"read_node_list",
+"Get a list of HCI nodes, their Netgraph IDs and connected hooks.",
+&hci_read_node_list
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/hccontrol/send_recv.c b/usr.sbin/hccontrol/send_recv.c
new file mode 100644
index 0000000000..a07bc04d65
--- /dev/null
+++ b/usr.sbin/hccontrol/send_recv.c
@@ -0,0 +1,184 @@
+/*
+ * send_recv.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: send_recv.c,v 1.2 2003/05/21 22:40:30 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/send_recv.c 128079 2004-04-09 23:58:53Z emax $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/endian.h>
+#include <assert.h>
+#include <errno.h>
+#include <netgraph7/bluetooth/include/ng_hci.h>
+#include <string.h>
+#include <unistd.h>
+#include "hccontrol.h"
+
+/* Send HCI request to the unit */
+int
+hci_request(int s, int opcode, char const *cp, int cp_size, char *rp, int *rp_size)
+{
+	char			 buffer[512];
+	int			 n;
+	ng_hci_cmd_pkt_t	*c = (ng_hci_cmd_pkt_t *) buffer;
+	ng_hci_event_pkt_t	*e = (ng_hci_event_pkt_t *) buffer;
+
+	assert(rp != NULL);
+	assert(rp_size != NULL);
+	assert(*rp_size > 0);
+
+	c->type = NG_HCI_CMD_PKT;
+	c->opcode = (uint16_t) opcode;
+	c->opcode = htole16(c->opcode);
+
+	if (cp != NULL) {
+		assert(0 < cp_size && cp_size <= NG_HCI_CMD_PKT_SIZE);
+
+		c->length = (uint8_t) cp_size;
+		memcpy(buffer + sizeof(*c), cp, cp_size);
+	} else
+		c->length = 0;
+
+	if (hci_send(s, buffer, sizeof(*c) + cp_size) == ERROR)
+		return (ERROR);
+
+again:
+	n = sizeof(buffer);
+	if (hci_recv(s, buffer, &n) == ERROR)
+		return (ERROR);
+
+	if (n < sizeof(*e)) {
+		errno = EMSGSIZE;
+		return (ERROR);
+	}
+
+	if (e->type != NG_HCI_EVENT_PKT) {
+		errno = EIO;
+		return (ERROR);
+	}
+
+	switch (e->event) {
+	case NG_HCI_EVENT_COMMAND_COMPL: {
+		ng_hci_command_compl_ep	*cc = 
+				(ng_hci_command_compl_ep *)(e + 1);
+
+		cc->opcode = le16toh(cc->opcode);
+
+		if (cc->opcode == 0x0000 || cc->opcode != opcode)
+			goto again; 
+
+		n -= (sizeof(*e) + sizeof(*cc));
+		if (n < *rp_size)
+			*rp_size = n;
+
+		memcpy(rp, buffer + sizeof(*e) + sizeof(*cc), *rp_size);
+		} break;
+
+	case NG_HCI_EVENT_COMMAND_STATUS: {
+		ng_hci_command_status_ep	*cs = 
+				(ng_hci_command_status_ep *)(e + 1);
+
+		cs->opcode = le16toh(cs->opcode);
+
+		if (cs->opcode == 0x0000 || cs->opcode != opcode)
+			goto again; 
+
+		*rp_size = 1;
+		*rp = cs->status;
+		} break;
+
+	default:
+		goto again;
+	}
+
+	return (OK);
+} /* hci_request */
+
+/* Send simple HCI request - Just HCI command packet (no parameters) */
+int
+hci_simple_request(int s, int opcode, char *rp, int *rp_size)
+{
+	return (hci_request(s, opcode, NULL, 0, rp, rp_size));
+} /* hci_simple_request */
+
+/* Send HCI data to the unit */
+int
+hci_send(int s, char const *buffer, int size)
+{
+	assert(buffer != NULL);
+	assert(size >= sizeof(ng_hci_cmd_pkt_t));
+	assert(size <= sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE);
+
+	if (send(s, buffer, size, 0) < 0)
+		return (ERROR);
+
+	return (OK);
+} /* hci_send */
+
+/* Receive HCI data from the unit */
+int
+hci_recv(int s, char *buffer, int *size)
+{
+	struct timeval	tv;
+	fd_set		rfd;
+	int		n;
+
+	assert(buffer != NULL);
+	assert(size != NULL);
+	assert(*size > sizeof(ng_hci_event_pkt_t));
+
+again:
+	FD_ZERO(&rfd);
+	FD_SET(s, &rfd);
+
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+
+	n = select(s + 1, &rfd, NULL, NULL, &tv);
+	if (n <= 0) {
+		if (n < 0) {
+			if (errno == EINTR)
+				goto again;
+		} else
+			errno = ETIMEDOUT;
+
+		return (ERROR);
+	}
+
+	assert(FD_ISSET(s, &rfd));
+
+	n = recv(s, buffer, *size, 0);
+	if (n < 0)
+		return (ERROR);
+
+	*size = n;
+
+	return (OK);
+} /* hci_recv */
+
diff --git a/usr.sbin/hccontrol/status.c b/usr.sbin/hccontrol/status.c
new file mode 100644
index 0000000000..cf6045a581
--- /dev/null
+++ b/usr.sbin/hccontrol/status.c
@@ -0,0 +1,245 @@
+/*
+ * status.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: status.c,v 1.2 2003/05/21 22:40:30 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/status.c 128079 2004-04-09 23:58:53Z emax $
+ */
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <errno.h>
+#include <netgraph7/bluetooth/include/ng_hci.h>
+#include <stdio.h>
+#include "hccontrol.h"
+
+/* Send Read_Failed_Contact_Counter command to the unit */
+static int
+hci_read_failed_contact_counter(int s, int argc, char **argv)
+{
+	ng_hci_read_failed_contact_cntr_cp	cp;
+	ng_hci_read_failed_contact_cntr_rp	rp;
+	int					n;
+
+	switch (argc) {
+	case 1:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+  
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	} 
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
+			NG_HCI_OCF_READ_FAILED_CONTACT_CNTR),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
+	fprintf(stdout, "Failed contact counter: %d\n", le16toh(rp.counter));
+
+	return (OK);
+} /* hci_read_failed_contact_counter */
+
+/* Send Reset_Failed_Contact_Counter command to the unit */
+static int
+hci_reset_failed_contact_counter(int s, int argc, char **argv)
+{
+	ng_hci_reset_failed_contact_cntr_cp	cp;
+	ng_hci_reset_failed_contact_cntr_rp	rp;
+	int					n;
+
+	switch (argc) {
+	case 1:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+  
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
+			NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+	
+	return (OK);
+} /* hci_reset_failed_contact_counter */
+
+/* Sent Get_Link_Quality command to the unit */
+static int
+hci_get_link_quality(int s, int argc, char **argv)
+{
+	ng_hci_get_link_quality_cp	cp;
+	ng_hci_get_link_quality_rp	rp;
+	int				n;
+
+	switch (argc) {
+	case 1:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+  
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
+			NG_HCI_OCF_GET_LINK_QUALITY),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
+	fprintf(stdout, "Link quality: %d\n", le16toh(rp.quality));
+	
+	return (OK);
+} /* hci_get_link_quality */
+
+/* Send Read_RSSI command to the unit */
+static int
+hci_read_rssi(int s, int argc, char **argv)
+{
+	ng_hci_read_rssi_cp	cp;
+	ng_hci_read_rssi_rp	rp;
+	int			n;
+	
+	switch (argc) {
+	case 1:
+		/* connection handle */
+		if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff)
+			return (USAGE);
+  
+		cp.con_handle = (uint16_t) (n & 0x0fff);
+		cp.con_handle = htole16(cp.con_handle);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	/* send command */
+	n = sizeof(rp);
+	if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_STATUS,
+			NG_HCI_OCF_READ_RSSI),
+			(char const *) &cp, sizeof(cp),
+			(char *) &rp, &n) == ERROR)
+		return (ERROR);
+
+	if (rp.status != 0x00) {
+		fprintf(stdout, "Status: %s [%#02x]\n", 
+			hci_status2str(rp.status), rp.status);
+		return (FAILED);
+	}
+
+	fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle));
+	fprintf(stdout, "RSSI: %d dB\n", (int) rp.rssi);
+	
+	return (OK);
+} /* hci_read_rssi */
+
+struct hci_command	status_commands[] = {
+{
+"read_failed_contact_counter <connection_handle>",
+"\nThis command will read the value for the Failed_Contact_Counter\n" \
+"parameter for a particular ACL connection to another device.\n\n" \
+"\t<connection_handle> - dddd; ACL connection handle\n",
+&hci_read_failed_contact_counter
+},
+{
+"reset_failed_contact_counter <connection_handle>",
+"\nThis command will reset the value for the Failed_Contact_Counter\n" \
+"parameter for a particular ACL connection to another device.\n\n" \
+"\t<connection_handle> - dddd; ACL connection handle\n",
+&hci_reset_failed_contact_counter
+},
+{
+"get_link_quality <connection_handle>",
+"\nThis command will return the value for the Link_Quality for the\n" \
+"specified ACL connection handle. This command will return a Link_Quality\n" \
+"value from 0-255, which represents the quality of the link between two\n" \
+"Bluetooth devices. The higher the value, the better the link quality is.\n" \
+"Each Bluetooth module vendor will determine how to measure the link quality." \
+"\n\n" \
+"\t<connection_handle> - dddd; ACL connection handle\n", 
+&hci_get_link_quality
+},
+{
+"read_rssi <connection_handle>",
+"\nThis command will read the value for the difference between the\n" \
+"measured Received Signal Strength Indication (RSSI) and the limits of\n" \
+"the Golden Receive Power Range for a ACL connection handle to another\n" \
+"Bluetooth device. Any positive RSSI value returned by the Host Controller\n" \
+"indicates how many dB the RSSI is above the upper limit, any negative\n" \
+"value indicates how many dB the RSSI is below the lower limit. The value\n" \
+"zero indicates that the RSSI is inside the Golden Receive Power Range.\n\n" \
+"\t<connection_handle> - dddd; ACL connection handle\n", 
+&hci_read_rssi
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/hccontrol/util.c b/usr.sbin/hccontrol/util.c
new file mode 100644
index 0000000000..baf5091aa2
--- /dev/null
+++ b/usr.sbin/hccontrol/util.c
@@ -0,0 +1,410 @@
+/*
+ * util.c
+ *
+ * Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: util.c,v 1.2 2003/05/19 17:29:29 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/util.c 162495 2006-09-21 02:41:04Z emax $
+ */
+ 
+#include <sys/param.h>
+#include <bluetooth.h>
+#include <stdio.h>
+#include <string.h>
+
+#define SIZE(x) (sizeof((x))/sizeof((x)[0]))
+
+char const *
+hci_link2str(int link_type)
+{
+	static char const * const	t[] = {
+		/* NG_HCI_LINK_SCO */ "SCO",
+		/* NG_HCI_LINK_ACL */ "ACL"
+	};
+
+	return (link_type >= SIZE(t)? "?" : t[link_type]);
+} /* hci_link2str */
+
+char const *
+hci_pin2str(int type)
+{
+	static char const * const	t[] = {
+		/* 0x00 */ "Variable PIN",
+		/* 0x01 */ "Fixed PIN"
+	};
+
+	return (type >= SIZE(t)? "?" : t[type]);
+} /* hci_pin2str */
+
+char const *
+hci_scan2str(int scan)
+{
+	static char const * const	t[] = {
+		/* 0x00 */ "No Scan enabled",
+		/* 0x01 */ "Inquiry Scan enabled. Page Scan disabled",
+		/* 0x02 */ "Inquiry Scan disabled. Page Scan enabled",
+		/* 0x03 */ "Inquiry Scan enabled. Page Scan enabled"
+	};
+
+	return (scan >= SIZE(t)? "?" : t[scan]);
+} /* hci_scan2str */
+
+char const *
+hci_encrypt2str(int encrypt, int brief)
+{
+	static char const * const	t[] = {
+		/* 0x00 */ "Disabled",
+		/* 0x01 */ "Only for point-to-point packets",
+		/* 0x02 */ "Both point-to-point and broadcast packets"
+	};
+
+	static char const * const	t1[] = {
+		/* NG_HCI_ENCRYPTION_MODE_NONE */ "NONE",
+		/* NG_HCI_ENCRYPTION_MODE_P2P */  "P2P",
+		/* NG_HCI_ENCRYPTION_MODE_ALL */  "ALL",
+	};
+
+	if (brief)
+		return (encrypt >= SIZE(t1)? "?" : t1[encrypt]);
+
+	return (encrypt >= SIZE(t)? "?" : t[encrypt]);
+} /* hci_encrypt2str */
+
+char const *
+hci_coding2str(int coding)
+{
+	static char const * const	t[] = {
+		/* 0x00 */ "Linear",
+		/* 0x01 */ "u-law",
+		/* 0x02 */ "A-law",
+		/* 0x03 */ "Reserved"
+	};
+
+	return (coding >= SIZE(t)? "?" : t[coding]);
+} /* hci_coding2str */
+
+char const *
+hci_vdata2str(int data)
+{
+	static char const * const	t[] = {
+		/* 0x00 */ "1's complement",
+		/* 0x01 */ "2's complement",
+		/* 0x02 */ "Sign-Magnitude",
+		/* 0x03 */ "Reserved"
+	};
+
+	return (data >= SIZE(t)? "?" : t[data]);
+} /* hci_vdata2str */
+
+char const *
+hci_hmode2str(int mode, char *buffer, int size)
+{
+	static char const * const	t[] = {
+		/* 0x01 */ "Suspend Page Scan ",
+		/* 0x02 */ "Suspend Inquiry Scan ",
+		/* 0x04 */ "Suspend Periodic Inquiries "
+        };
+
+	if (buffer != NULL && size > 0) {
+		int	n;
+
+		memset(buffer, 0, size);
+		for (n = 0; n < SIZE(t); n++) {
+			int	len = strlen(buffer);
+
+			if (len >= size)
+				break;
+			if (mode & (1 << n))
+				strncat(buffer, t[n], size - len);
+		}
+	}
+
+	return (buffer);
+} /* hci_hmode2str */
+
+char const *
+hci_ver2str(int ver)
+{
+	static char const * const	t[] = {
+		/* 0x00 */ "Bluetooth HCI Specification 1.0B",
+		/* 0x01 */ "Bluetooth HCI Specification 1.1",
+		/* 0x02 */ "Bluetooth HCI Specification 1.2",
+		/* 0x03 */ "Bluetooth HCI Specification 2.0"
+	};
+
+	return (ver >= SIZE(t)? "?" : t[ver]);
+} /* hci_ver2str */
+
+char const *
+hci_lmpver2str(int ver)
+{
+	static char const * const	t[] = {
+		/* 0x00 */ "Bluetooth LMP 1.0",
+		/* 0x01 */ "Bluetooth LMP 1.1",
+		/* 0x02 */ "Bluetooth LMP 1.2",
+		/* 0x03 */ "Bluetooth LMP 2.0"
+	};
+
+	return (ver >= SIZE(t)? "?" : t[ver]);
+} /* hci_lmpver2str */
+
+char const *
+hci_manufacturer2str(int m)
+{
+	static char const * const	t[] = {
+		/* 0000 */ "Ericsson Technology Licensing",
+		/* 0001 */ "Nokia Mobile Phones",
+		/* 0002 */ "Intel Corp.",
+		/* 0003 */ "IBM Corp.",
+		/* 0004 */ "Toshiba Corp.",
+		/* 0005 */ "3Com",
+		/* 0006 */ "Microsoft",
+		/* 0007 */ "Lucent",
+		/* 0008 */ "Motorola",
+		/* 0009 */ "Infineon Technologies AG",
+		/* 0010 */ "Cambridge Silicon Radio",
+		/* 0011 */ "Silicon Wave",
+		/* 0012 */ "Digianswer A/S",
+		/* 0013 */ "Texas Instruments Inc.",
+		/* 0014 */ "Parthus Technologies Inc.",
+		/* 0015 */ "Broadcom Corporation",
+		/* 0016 */ "Mitel Semiconductor",
+		/* 0017 */ "Widcomm, Inc.",
+		/* 0018 */ "Zeevo, Inc.",
+		/* 0019 */ "Atmel Corporation",
+		/* 0020 */ "Mitsubishi Electric Corporation",
+		/* 0021 */ "RTX Telecom A/S",
+		/* 0022 */ "KC Technology Inc.",
+		/* 0023 */ "Newlogic",
+		/* 0024 */ "Transilica, Inc.",
+		/* 0025 */ "Rohde & Schwartz GmbH & Co. KG",
+		/* 0026 */ "TTPCom Limited",
+		/* 0027 */ "Signia Technologies, Inc.",
+		/* 0028 */ "Conexant Systems Inc.",
+		/* 0029 */ "Qualcomm",
+		/* 0030 */ "Inventel",
+		/* 0031 */ "AVM Berlin",
+		/* 0032 */ "BandSpeed, Inc.",
+		/* 0033 */ "Mansella Ltd",
+		/* 0034 */ "NEC Corporation",
+		/* 0035 */ "WavePlus Technology Co., Ltd.",
+		/* 0036 */ "Alcatel",
+		/* 0037 */ "Philips Semiconductors",
+		/* 0038 */ "C Technologies",
+		/* 0039 */ "Open Interface",
+		/* 0040 */ "R F Micro Devices",
+		/* 0041 */ "Hitachi Ltd",
+		/* 0042 */ "Symbol Technologies, Inc.",
+		/* 0043 */ "Tenovis",
+		/* 0044 */ "Macronix International Co. Ltd.",
+		/* 0045 */ "GCT Semiconductor",
+		/* 0046 */ "Norwood Systems",
+		/* 0047 */ "MewTel Technology Inc.",
+		/* 0048 */ "ST Microelectronics",
+		/* 0049 */ "Synopsys",
+		/* 0050 */ "Red-M (Communications) Ltd",
+		/* 0051 */ "Commil Ltd",
+		/* 0052 */ "Computer Access Technology Corporation (CATC)",
+		/* 0053 */ "Eclipse (HQ Espana) S.L.",
+		/* 0054 */ "Renesas Technology Corp.",
+		/* 0055 */ "Mobilian Corporation",
+		/* 0056 */ "Terax",
+		/* 0057 */ "Integrated System Solution Corp.",
+		/* 0058 */ "Matsushita Electric Industrial Co., Ltd.",
+		/* 0059 */ "Gennum Corporation",
+		/* 0060 */ "Research In Motion",
+		/* 0061 */ "IPextreme, Inc.",
+		/* 0062 */ "Systems and Chips, Inc",
+		/* 0063 */ "Bluetooth SIG, Inc",
+		/* 0064 */ "Seiko Epson Corporation"
+        };
+
+	return (m >= SIZE(t)? "?" : t[m]);
+} /* hci_manufacturer2str */
+
+char const *
+hci_features2str(uint8_t *features, char *buffer, int size)
+{
+	static char const * const	t[][8] = {
+	{ /* byte 0 */
+		/* 0 */ "<3-Slot> ",
+		/* 1 */ "<5-Slot> ",
+		/* 2 */ "<Encryption> ",
+		/* 3 */ "<Slot offset> ",
+		/* 4 */ "<Timing accuracy> ",
+		/* 5 */ "<Switch> ",
+		/* 6 */ "<Hold mode> ",
+		/* 7 */ "<Sniff mode> "
+	},
+	{ /* byte 1 */
+		/* 0 */ "<Park mode> ",
+		/* 1 */ "<RSSI> ",
+		/* 2 */ "<Channel quality> ",
+		/* 3 */ "<SCO link> ",
+		/* 4 */ "<HV2 packets> ",
+		/* 5 */ "<HV3 packets> ",
+		/* 6 */ "<u-law log> ",
+		/* 7 */ "<A-law log> "
+	},
+	{ /* byte 2 */
+		/* 0 */ "<CVSD> ",
+		/* 1 */ "<Paging scheme> ",
+		/* 2 */ "<Power control> ",
+		/* 3 */ "<Transparent SCO data> ",
+		/* 4 */ "<Flow control lag (bit0)> ",
+		/* 5 */ "<Flow control lag (bit1)> ",
+		/* 6 */ "<Flow control lag (bit2)> ",
+		/* 7 */ "<Unknown2.7> "
+	}};
+
+	if (buffer != NULL && size > 0) {
+		int	n, i, len0, len1;
+
+		memset(buffer, 0, size);
+		len1 = 0;
+
+		for (n = 0; n < SIZE(t); n++) {
+			for (i = 0; i < SIZE(t[n]); i++) {
+				len0 = strlen(buffer);
+				if (len0 >= size)
+					goto done;
+
+				if (features[n] & (1 << i)) {
+					if (len1 + strlen(t[n][i]) > 60) {
+						len1 = 0;
+						buffer[len0 - 1] = '\n';
+					}
+
+					len1 += strlen(t[n][i]);
+					strncat(buffer, t[n][i], size - len0);
+				}
+			}
+		}
+	}
+done:
+	return (buffer);
+} /* hci_features2str */
+
+char const *
+hci_cc2str(int cc)
+{
+	static char const * const	t[] = {
+		/* 0x00 */ "North America, Europe, Japan",
+		/* 0x01 */ "France"
+	};
+
+	return (cc >= SIZE(t)? "?" : t[cc]);
+} /* hci_cc2str */
+
+char const *
+hci_con_state2str(int state)
+{
+	static char const * const	t[] = {
+		/* NG_HCI_CON_CLOSED */           "CLOSED",
+		/* NG_HCI_CON_W4_LP_CON_RSP */    "W4_LP_CON_RSP",
+		/* NG_HCI_CON_W4_CONN_COMPLETE */ "W4_CONN_COMPLETE",
+		/* NG_HCI_CON_OPEN */             "OPEN"
+        };
+
+	return (state >= SIZE(t)? "UNKNOWN" : t[state]);
+} /* hci_con_state2str */
+
+char const *
+hci_status2str(int status)
+{
+	static char const * const       t[] = {
+		/* 0x00 */ "No error",
+		/* 0x01 */ "Unknown HCI command",
+		/* 0x02 */ "No connection",
+		/* 0x03 */ "Hardware failure",
+		/* 0x04 */ "Page timeout",
+		/* 0x05 */ "Authentication failure",
+		/* 0x06 */ "Key missing",
+		/* 0x07 */ "Memory full",
+		/* 0x08 */ "Connection timeout",
+		/* 0x09 */ "Max number of connections",
+		/* 0x0a */ "Max number of SCO connections to a unit",
+		/* 0x0b */ "ACL connection already exists",
+		/* 0x0c */ "Command disallowed",
+		/* 0x0d */ "Host rejected due to limited resources",
+		/* 0x0e */ "Host rejected due to security reasons",
+		/* 0x0f */ "Host rejected due to remote unit is a personal unit",
+		/* 0x10 */ "Host timeout",
+		/* 0x11 */ "Unsupported feature or parameter value",
+		/* 0x12 */ "Invalid HCI command parameter",
+		/* 0x13 */ "Other end terminated connection: User ended connection",
+		/* 0x14 */ "Other end terminated connection: Low resources",
+		/* 0x15 */ "Other end terminated connection: About to power off",
+		/* 0x16 */ "Connection terminated by local host",
+		/* 0x17 */ "Repeated attempts",
+		/* 0x18 */ "Pairing not allowed",
+		/* 0x19 */ "Unknown LMP PDU",
+		/* 0x1a */ "Unsupported remote feature",
+		/* 0x1b */ "SCO offset rejected",
+		/* 0x1c */ "SCO interval rejected",
+		/* 0x1d */ "SCO air mode rejected",
+		/* 0x1e */ "Invalid LMP parameters",
+		/* 0x1f */ "Unspecified error",
+		/* 0x20 */ "Unsupported LMP parameter value",
+		/* 0x21 */ "Role change not allowed",
+		/* 0x22 */ "LMP response timeout",
+		/* 0x23 */ "LMP error transaction collision",
+		/* 0x24 */ "LMP PSU not allowed",
+		/* 0x25 */ "Encryption mode not acceptable",
+		/* 0x26 */ "Unit key used",
+		/* 0x27 */ "QoS is not supported",
+		/* 0x28 */ "Instant passed",
+		/* 0x29 */ "Pairing with unit key not supported"
+	};
+
+	return (status >= SIZE(t)? "Unknown error" : t[status]);
+} /* hci_status2str */
+
+char const *
+hci_bdaddr2str(bdaddr_t const *ba)
+{
+	extern int	 numeric_bdaddr;
+	static char	 buffer[MAXHOSTNAMELEN];
+	struct hostent	*he = NULL;
+
+	if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
+		buffer[0] = '*';
+		buffer[1] = 0;
+
+		return (buffer);
+	}
+
+	if (!numeric_bdaddr &&
+	    (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
+		strlcpy(buffer, he->h_name, sizeof(buffer));
+
+		return (buffer);
+	}
+
+	bt_ntoa(ba, buffer);
+
+	return (buffer);
+} /* hci_bdaddr2str */
+
diff --git a/usr.sbin/hcsecd/Makefile b/usr.sbin/hcsecd/Makefile
new file mode 100644
index 0000000000..a174a5e11b
--- /dev/null
+++ b/usr.sbin/hcsecd/Makefile
@@ -0,0 +1,13 @@
+# $Id: Makefile,v 1.8 2003/08/14 20:06:20 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/hcsecd/Makefile 135245 2004-09-14 20:04:33Z emax $
+
+PROG=		hcsecd
+MAN=		hcsecd.8 hcsecd.conf.5
+SRCS=		hcsecd.c lexer.l parser.y
+WARNS?=		2
+CFLAGS+=	-I${.CURDIR}
+
+DPADD=		${LIBBLUETOOTH}
+LDADD=		-lbluetooth
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/hcsecd/hcsecd.8 b/usr.sbin/hcsecd/hcsecd.8
new file mode 100644
index 0000000000..9b868899da
--- /dev/null
+++ b/usr.sbin/hcsecd/hcsecd.8
@@ -0,0 +1,128 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: hcsecd.8,v 1.8 2003/09/08 18:54:20 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/hcsecd/hcsecd.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd November 16, 2002
+.Dt HCSECD 8
+.Os
+.Sh NAME
+.Nm hcsecd
+.Nd control link keys and PIN codes for Bluetooth devices
+.Sh SYNOPSIS
+.Nm
+.Op Fl dh
+.Fl f Ar configfile
+.Sh DESCRIPTION
+The
+.Nm
+daemon controls link keys and PIN codes for Bluetooth devices.
+It opens a raw HCI socket and listens for
+.Dv Link_Key_Request ,
+.Dv PIN_Code_Request
+and
+.Dv Link_Key_Notification
+HCI events.
+.Pp
+Once a
+.Dv Link_Key_Request
+or
+.Dv PIN_Code_Request
+HCI event is received, the daemon scans the configuration file for a
+matching entry.
+The remote device BD_ADDR is used as a key.
+If no matching entry was found, the default entry will be used.
+If no default entry was found then it is assumed that no link key and no
+PIN code exists.
+For any given entry, the link key takes precedence over the PIN code.
+If a link key was not specified, the device must generate the link key from
+the PIN code.
+If an entry was found and the link key (or PIN code) exists, the
+.Dv Link_Key_Request_Reply
+(or
+.Dv PIN_Code_Request_Reply )
+command will be sent back to the device.
+Otherwise, the
+.Dv Link_Key_Request_Negative_Reply
+(or
+.Dv PIN_Code_Request_Negative_Reply )
+command will be sent back to the device.
+.Pp
+The
+.Nm
+daemon also handles HCI
+.Dv Link_Key_Notification
+events and caches link keys created from the PIN codes in memory.
+To preserve link keys between restarts the
+.Nm
+daemon dumps link keys for all entries in the
+.Pa /var/db/hcsecd.keys
+link keys file.
+If it exists, the link keys file gets processed by the
+.Nm
+daemon after it processes its main configuration file.
+The link keys file gets written every time the
+.Nm
+daemon shuts down gracefully.
+It is possible to force the
+.Nm
+daemon to re-read its main configuration file and dump the link keys file by
+sending the
+.Dv HUP
+signal to the
+.Nm
+process.
+The user is expected to not modify the link keys file by hand.
+.Pp
+The command line options are as follows:
+.Bl -tag -width indent
+.It Fl d
+Do not detach from the controlling terminal.
+.It Fl f Ar configfile
+Specify the name of the configuration file.
+The default is
+.Pa /etc/bluetooth/hcsecd.conf .
+.It Fl h
+Display usage message and exit.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/bluetooth/hcsecd.conf" -compact
+.It Pa /etc/bluetooth/hcsecd.conf
+.It Pa /var/db/hcsecd.keys
+.It Pa /var/run/hcsecd.pid
+.El
+.Sh SEE ALSO
+.Xr ng_btsocket 4 ,
+.Xr ng_hci 4 ,
+.Xr hcsecd.conf 5 ,
+.Xr hccontrol 8 ,
+.Xr hcseriald 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh BUGS
+Currently there is no way to select the link key or the PIN code based on
+which local device received the request.
+Everything is based on the remote device BD_ADDR.
+An interface for external helpers to obtain link keys and PIN codes is missing.
diff --git a/usr.sbin/hcsecd/hcsecd.c b/usr.sbin/hcsecd/hcsecd.c
new file mode 100644
index 0000000000..2835b4a531
--- /dev/null
+++ b/usr.sbin/hcsecd/hcsecd.c
@@ -0,0 +1,446 @@
+/*
+ * hcsecd.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: hcsecd.c,v 1.6 2003/08/18 19:19:55 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hcsecd/hcsecd.c 188130 2009-02-04 22:04:06Z emax $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "hcsecd.h"
+
+static int	done = 0;
+
+static int process_pin_code_request_event
+	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);
+static int process_link_key_request_event
+	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);
+static int send_pin_code_reply
+	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, char const *pin);
+static int send_link_key_reply
+	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, uint8_t *key);
+static int process_link_key_notification_event
+	(int sock, struct sockaddr_hci *addr, ng_hci_link_key_notification_ep *ep);
+static void sighup
+	(int s);
+static void sigint
+	(int s);
+static void usage
+	(void);
+
+/* Main */
+int
+main(int argc, char *argv[])
+{
+	int					 n, detach, sock;
+	socklen_t				 size;
+	struct sigaction			 sa;
+	struct sockaddr_hci			 addr;
+	struct ng_btsocket_hci_raw_filter	 filter;
+	char					 buffer[HCSECD_BUFFER_SIZE];
+	ng_hci_event_pkt_t			*event = NULL;
+
+	detach = 1;
+
+	while ((n = getopt(argc, argv, "df:h")) != -1) {
+		switch (n) {
+		case 'd':
+			detach = 0;
+			break;
+
+		case 'f':
+			config_file = optarg;
+			break;
+
+		case 'h':
+		default:
+			usage();
+			/* NOT REACHED */
+		}
+	}
+
+	if (config_file == NULL)
+		usage();
+		/* NOT REACHED */
+
+	if (getuid() != 0)
+		errx(1, "** ERROR: You should run %s as privileged user!",
+			HCSECD_IDENT);
+
+	/* Set signal handlers */
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = sigint;
+	sa.sa_flags = SA_NOCLDWAIT;
+	if (sigaction(SIGINT, &sa, NULL) < 0)
+		err(1, "Could not sigaction(SIGINT)");
+	if (sigaction(SIGTERM, &sa, NULL) < 0)
+		err(1, "Could not sigaction(SIGINT)");
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = sighup;
+	if (sigaction(SIGHUP, &sa, NULL) < 0)
+		err(1, "Could not sigaction(SIGHUP)");
+
+	/* Open socket and set filter */
+	sock = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
+	if (sock < 0)
+		err(1, "Could not create HCI socket");
+
+	memset(&filter, 0, sizeof(filter));
+	bit_set(filter.event_mask, NG_HCI_EVENT_PIN_CODE_REQ - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_REQ - 1);
+	bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_NOTIFICATION - 1);
+
+	if (setsockopt(sock, SOL_HCI_RAW, SO_HCI_RAW_FILTER,
+			(void * const) &filter, sizeof(filter)) < 0)
+		err(1, "Could not set HCI socket filter");
+
+	if (detach && daemon(0, 0) < 0)
+		err(1, "Could not daemon()ize");
+
+	openlog(HCSECD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON);
+
+	read_config_file();
+	read_keys_file();
+
+	if (detach) {
+		FILE	*pid = NULL;
+
+		if ((pid = fopen(HCSECD_PIDFILE, "w")) == NULL) {
+			syslog(LOG_ERR, "Could not create PID file %s. %s (%d)",
+					HCSECD_PIDFILE, strerror(errno), errno);
+			exit(1);
+		}
+
+		fprintf(pid, "%d", getpid());
+		fclose(pid);
+	}
+
+	event = (ng_hci_event_pkt_t *) buffer;
+	while (!done) {
+		size = sizeof(addr);
+		n = recvfrom(sock, buffer, sizeof(buffer), 0,
+				(struct sockaddr *) &addr, &size);
+		if (n < 0) {
+			if (errno == EINTR)
+				continue;
+
+			syslog(LOG_ERR, "Could not receive from HCI socket. " \
+					"%s (%d)", strerror(errno), errno);
+			exit(1);
+		}
+
+		if (event->type != NG_HCI_EVENT_PKT) {
+			syslog(LOG_ERR, "Received unexpected HCI packet, " \
+					"type=%#x", event->type);
+			continue;
+		}
+
+		switch (event->event) {
+		case NG_HCI_EVENT_PIN_CODE_REQ:
+			process_pin_code_request_event(sock, &addr,
+							(bdaddr_p)(event + 1));
+			break;
+
+		case NG_HCI_EVENT_LINK_KEY_REQ:
+			process_link_key_request_event(sock, &addr,
+							(bdaddr_p)(event + 1));
+			break;
+
+		case NG_HCI_EVENT_LINK_KEY_NOTIFICATION:
+			process_link_key_notification_event(sock, &addr,
+				(ng_hci_link_key_notification_ep *)(event + 1));
+			break;
+
+		default:
+			syslog(LOG_ERR, "Received unexpected HCI event, " \
+					"event=%#x", event->event);
+			break;
+		}
+	}
+
+	if (detach)
+		if (remove(HCSECD_PIDFILE) < 0)
+			syslog(LOG_ERR, "Could not remove PID file %s. %s (%d)",
+					HCSECD_PIDFILE, strerror(errno), errno);
+
+	dump_keys_file();
+	clean_config();
+	closelog();
+	close(sock);
+
+	return (0);
+}
+
+/* Process PIN_Code_Request event */
+static int
+process_pin_code_request_event(int sock, struct sockaddr_hci *addr,
+		bdaddr_p bdaddr)
+{
+	link_key_p	key = NULL;
+
+	syslog(LOG_DEBUG, "Got PIN_Code_Request event from '%s', " \
+			"remote bdaddr %s", addr->hci_node,
+			bt_ntoa(bdaddr, NULL));
+
+	if ((key = get_key(bdaddr, 0)) != NULL) {
+		syslog(LOG_DEBUG, "Found matching entry, " \
+				"remote bdaddr %s, name '%s', PIN code %s",
+				bt_ntoa(&key->bdaddr, NULL),
+				(key->name != NULL)? key->name : "No name",
+				(key->pin != NULL)? "exists" : "doesn't exist");
+
+		return (send_pin_code_reply(sock, addr, bdaddr, key->pin));
+	}
+
+	syslog(LOG_DEBUG, "Could not PIN code for remote bdaddr %s",
+			bt_ntoa(bdaddr, NULL));
+
+	return (send_pin_code_reply(sock, addr, bdaddr, NULL));
+}
+
+/* Process Link_Key_Request event */
+static int
+process_link_key_request_event(int sock, struct sockaddr_hci *addr,
+		bdaddr_p bdaddr)
+{
+	link_key_p	key = NULL;
+
+	syslog(LOG_DEBUG, "Got Link_Key_Request event from '%s', " \
+			"remote bdaddr %s", addr->hci_node,
+			bt_ntoa(bdaddr, NULL));
+
+	if ((key = get_key(bdaddr, 0)) != NULL) {
+		syslog(LOG_DEBUG, "Found matching entry, " \
+				"remote bdaddr %s, name '%s', link key %s",
+				bt_ntoa(&key->bdaddr, NULL),
+				(key->name != NULL)? key->name : "No name",
+				(key->key != NULL)? "exists" : "doesn't exist");
+
+		return (send_link_key_reply(sock, addr, bdaddr, key->key));
+	}
+
+	syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s",
+			bt_ntoa(bdaddr, NULL));
+
+	return (send_link_key_reply(sock, addr, bdaddr, NULL));
+}
+
+/* Send PIN_Code_[Negative]_Reply */
+static int
+send_pin_code_reply(int sock, struct sockaddr_hci *addr, 
+		bdaddr_p bdaddr, char const *pin)
+{
+	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
+	ng_hci_cmd_pkt_t	*cmd = NULL;
+
+	memset(buffer, 0, sizeof(buffer));
+
+	cmd = (ng_hci_cmd_pkt_t *) buffer;
+	cmd->type = NG_HCI_CMD_PKT;
+
+	if (pin != NULL) {
+		ng_hci_pin_code_rep_cp	*cp = NULL;
+
+		cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+						NG_HCI_OCF_PIN_CODE_REP));
+		cmd->length = sizeof(*cp);
+
+		cp = (ng_hci_pin_code_rep_cp *)(cmd + 1);
+		memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
+		strncpy((char *) cp->pin, pin, sizeof(cp->pin));
+		cp->pin_size = strlen((char const *) cp->pin);
+
+		syslog(LOG_DEBUG, "Sending PIN_Code_Reply to '%s' " \
+				"for remote bdaddr %s",
+				addr->hci_node, bt_ntoa(bdaddr, NULL));
+	} else {
+		ng_hci_pin_code_neg_rep_cp	*cp = NULL;
+
+		cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+						NG_HCI_OCF_PIN_CODE_NEG_REP));
+		cmd->length = sizeof(*cp);
+
+		cp = (ng_hci_pin_code_neg_rep_cp *)(cmd + 1);
+		memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
+
+		syslog(LOG_DEBUG, "Sending PIN_Code_Negative_Reply to '%s' " \
+				"for remote bdaddr %s",
+				addr->hci_node, bt_ntoa(bdaddr, NULL));
+	}
+
+again:
+	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+			(struct sockaddr *) addr, sizeof(*addr)) < 0) {
+		if (errno == EINTR)
+			goto again;
+
+		syslog(LOG_ERR, "Could not send PIN code reply to '%s' " \
+				"for remote bdaddr %s. %s (%d)",
+				addr->hci_node, bt_ntoa(bdaddr, NULL),
+				strerror(errno), errno);
+		return (-1);
+	}
+
+	return (0);
+}
+
+/* Send Link_Key_[Negative]_Reply */
+static int
+send_link_key_reply(int sock, struct sockaddr_hci *addr, 
+		bdaddr_p bdaddr, uint8_t *key)
+{
+	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
+	ng_hci_cmd_pkt_t	*cmd = NULL;
+
+	memset(buffer, 0, sizeof(buffer));
+
+	cmd = (ng_hci_cmd_pkt_t *) buffer;
+	cmd->type = NG_HCI_CMD_PKT;
+
+	if (key != NULL) {
+		ng_hci_link_key_rep_cp	*cp = NULL;
+
+		cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+						NG_HCI_OCF_LINK_KEY_REP));
+		cmd->length = sizeof(*cp);
+
+		cp = (ng_hci_link_key_rep_cp *)(cmd + 1);
+		memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
+		memcpy(&cp->key, key, sizeof(cp->key));
+
+		syslog(LOG_DEBUG, "Sending Link_Key_Reply to '%s' " \
+				"for remote bdaddr %s",
+				addr->hci_node, bt_ntoa(bdaddr, NULL));
+	} else {
+		ng_hci_link_key_neg_rep_cp	*cp = NULL;
+
+		cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+						NG_HCI_OCF_LINK_KEY_NEG_REP));
+		cmd->length = sizeof(*cp);
+
+		cp = (ng_hci_link_key_neg_rep_cp *)(cmd + 1);
+		memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
+
+		syslog(LOG_DEBUG, "Sending Link_Key_Negative_Reply to '%s' " \
+				"for remote bdaddr %s",
+				addr->hci_node, bt_ntoa(bdaddr, NULL));
+	}
+
+again:
+	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+			(struct sockaddr *) addr, sizeof(*addr)) < 0) {
+		if (errno == EINTR)
+			goto again;
+
+		syslog(LOG_ERR, "Could not send link key reply to '%s' " \
+				"for remote bdaddr %s. %s (%d)",
+				addr->hci_node, bt_ntoa(bdaddr, NULL),
+				strerror(errno), errno);
+		return (-1);
+	}
+
+	return (0);
+}
+
+/* Process Link_Key_Notification event */
+static int
+process_link_key_notification_event(int sock, struct sockaddr_hci *addr,
+		ng_hci_link_key_notification_ep *ep)
+{
+	link_key_p	key = NULL;
+
+	syslog(LOG_DEBUG, "Got Link_Key_Notification event from '%s', " \
+			"remote bdaddr %s", addr->hci_node,
+			bt_ntoa(&ep->bdaddr, NULL));
+
+	if ((key = get_key(&ep->bdaddr, 1)) == NULL) {
+		syslog(LOG_ERR, "Could not find entry for remote bdaddr %s",
+				bt_ntoa(&ep->bdaddr, NULL));
+		return (-1);
+	}
+
+	syslog(LOG_DEBUG, "Updating link key for the entry, " \
+			"remote bdaddr %s, name '%s', link key %s",
+			bt_ntoa(&key->bdaddr, NULL),
+			(key->name != NULL)? key->name : "No name",
+			(key->key != NULL)? "exists" : "doesn't exist");
+
+	if (key->key == NULL) {
+		key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE);
+		if (key->key == NULL) {
+			syslog(LOG_ERR, "Could not allocate link key");
+			exit(1);
+		}
+	}
+
+	memcpy(key->key, &ep->key, NG_HCI_KEY_SIZE);
+
+	return (0);
+}
+
+/* Signal handlers */
+static void
+sighup(int s)
+{
+	syslog(LOG_DEBUG, "Got SIGHUP (%d)", s);
+
+	dump_keys_file();
+	read_config_file();
+	read_keys_file();
+}
+
+static void
+sigint(int s)
+{
+	syslog(LOG_DEBUG, "Got signal %d, total number of signals %d",
+			s, ++ done);
+}
+
+/* Display usage and exit */
+static void
+usage(void)
+{
+	fprintf(stderr,
+"Usage: %s [-d] -f config_file [-h]\n" \
+"Where:\n" \
+"\t-d              do not detach from terminal\n" \
+"\t-f config_file  use <config_file>\n" \
+"\t-h              display this message\n", HCSECD_IDENT);
+
+	exit(255);
+}
+
diff --git a/etc/bluetooth/bthcid.conf b/usr.sbin/hcsecd/hcsecd.conf
similarity index 63%
rename from etc/bluetooth/bthcid.conf
rename to usr.sbin/hcsecd/hcsecd.conf
index 0aaf4c5fa4..dd895f4731 100644
--- a/etc/bluetooth/bthcid.conf
+++ b/usr.sbin/hcsecd/hcsecd.conf
@@ -1,5 +1,6 @@
-# $FreeBSD: src/usr.sbin/bluetooth/hcsecd/hcsecd.conf,v 1.1 2003/05/10 21:50:35 julian Exp $
-# $DragonFly: src/etc/bluetooth/bthcid.conf,v 1.1 2008/01/30 14:10:19 hasso Exp $
+#
+# $Id: hcsecd.conf,v 1.1 2002/11/24 20:22:39 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/hcsecd/hcsecd.conf 114879 2003-05-10 21:50:37Z julian $
 #
 # HCI security daemon configuration file
 #
@@ -40,24 +41,24 @@ device {
 	pin	nopin;
 }
 
-# device {
-# 	bdaddr	00:80:37:5e:4d:d4;
-# 	name	"Ericsson T68 phone";
-# 	key	nokey;
-# 	pin	"0000"; # PIN code (string up to 16 character)
-# }
-# 
-# device {
-# 	bdaddr	00:01:03:fc:6e:ec;
-# 	name	"3COM PCCARD";
-# 	key	nokey;
-# 	pin	"0000";
-# }
-# 
-# device {
-# 	bdaddr	00:11:22:33:44:55;
-# 	name	"Dummy";
-# 	key	0x00112233445566778899aabbccddeeff; # 16 bytes key (hex string)
-# 	pin	nopin;
-# }
+device {
+	bdaddr	00:80:37:5e:4d:d4;
+	name	"Ericsson T68 phone";
+	key	nokey;
+	pin	"0000"; # PIN code (string up to 16 character)
+}
+
+device {
+	bdaddr	00:01:03:fc:6e:ec;
+	name	"3COM PCCARD";
+	key	nokey;
+	pin	"0000";
+}
+
+device {
+	bdaddr	00:11:22:33:44:55;
+	name	"Dummy";
+	key	0x00112233445566778899aabbccddeeff; # 16 bytes key (hex string)
+	pin	nopin;
+}
 
diff --git a/usr.sbin/bthcid/bthcid.conf.5 b/usr.sbin/hcsecd/hcsecd.conf.5
similarity index 95%
rename from usr.sbin/bthcid/bthcid.conf.5
rename to usr.sbin/hcsecd/hcsecd.conf.5
index d03ddc68dd..b501c0b974 100644
--- a/usr.sbin/bthcid/bthcid.conf.5
+++ b/usr.sbin/hcsecd/hcsecd.conf.5
@@ -23,21 +23,21 @@
 .\" SUCH DAMAGE.
 .\"
 .\" $Id: hcsecd.conf.5,v 1.1 2003/05/26 22:49:23 max Exp $
-.\" $FreeBSD: src/usr.sbin/bluetooth/hcsecd/hcsecd.conf.5,v 1.2 2004/06/13 18:03:40 ru Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/hcsecd/hcsecd.conf.5 267668 2014-06-20 09:57:27Z bapt $
 .\"
 .Dd May 26, 2003
-.Dt BTHCID.CONF 5
+.Dt HCSECD.CONF 5
 .Os
 .Sh NAME
-.Nm bthcid.conf
+.Nm hcsecd.conf
 .Nd
-.Xr bthcid 8
+.Xr hcsecd 8
 configuration file
 .Sh DESCRIPTION
 The
 .Nm
 file is the configuration file for the
-.Xr bthcid 8
+.Xr hcsecd 8
 Bluetooth link keys/PIN codes management daemon.
 .Pp
 The
@@ -46,7 +46,7 @@ file is a free-form
 .Tn ASCII
 text file.
 It is parsed by the recursive-descent parser built into
-.Xr bthcid 8 .
+.Xr hcsecd 8 .
 The file may contain extra tabs and newlines for formatting purposes.
 Keywords in the file are case-sensitive.
 Comments may be placed anywhere within the file (except within quotes).
@@ -126,6 +126,6 @@ device {
 }
 .Ed
 .Sh SEE ALSO
-.Xr bthcid 8
+.Xr hcsecd 8
 .Sh AUTHORS
 .An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
diff --git a/usr.sbin/hcsecd/hcsecd.h b/usr.sbin/hcsecd/hcsecd.h
new file mode 100644
index 0000000000..886684813d
--- /dev/null
+++ b/usr.sbin/hcsecd/hcsecd.h
@@ -0,0 +1,65 @@
+/*
+ * hcsecd.h
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: hcsecd.h,v 1.3 2003/09/08 18:54:21 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hcsecd/hcsecd.h 128079 2004-04-09 23:58:53Z emax $
+ */
+
+#ifndef _HCSECD_H_
+#define _HCSECD_H_ 1
+
+#define HCSECD_BUFFER_SIZE	512
+#define HCSECD_IDENT		"hcsecd"
+#define HCSECD_PIDFILE		"/var/run/" HCSECD_IDENT ".pid"
+#define HCSECD_KEYSFILE		"/var/db/"  HCSECD_IDENT ".keys"
+
+struct link_key
+{
+	bdaddr_t		 bdaddr; /* remote device BDADDR */
+	char			*name;   /* remote device name */
+	uint8_t			*key;    /* link key (or NULL if no key) */
+	char			*pin;    /* pin (or NULL if no pin) */
+	LIST_ENTRY(link_key)	 next;   /* link to the next */
+};
+typedef struct link_key		link_key_t;
+typedef struct link_key *	link_key_p;
+
+extern char	*config_file;
+
+#if __config_debug__
+void		dump_config	(void);
+#endif
+
+void		read_config_file(void);
+void		clean_config	(void);
+link_key_p	get_key		(bdaddr_p bdaddr, int exact_match);
+
+int		read_keys_file  (void);
+int		dump_keys_file  (void);
+
+#endif /* ndef _HCSECD_H_ */
+
diff --git a/usr.sbin/bthcid/lexer.l b/usr.sbin/hcsecd/lexer.l
similarity index 94%
rename from usr.sbin/bthcid/lexer.l
rename to usr.sbin/hcsecd/lexer.l
index 11f3a48c8f..7d50a93194 100644
--- a/usr.sbin/bthcid/lexer.l
+++ b/usr.sbin/hcsecd/lexer.l
@@ -27,16 +27,14 @@
  * SUCH DAMAGE.
  *
  * $Id: lexer.l,v 1.1 2002/11/24 20:22:39 max Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/hcsecd/lexer.l,v 1.1 2003/05/10 21:50:35 julian Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hcsecd/lexer.l 215676 2010-11-22 14:16:22Z brucec $
  */
 
 #include <string.h>
 #include "parser.h"
-
 %}
 
-%option yylineno noyywrap nounput
-%option noinput
+%option yylineno noyywrap nounput noinput
 
 delim		[ \t\n]
 ws		{delim}+
diff --git a/usr.sbin/bthcid/parser.y b/usr.sbin/hcsecd/parser.y
similarity index 71%
rename from usr.sbin/bthcid/parser.y
rename to usr.sbin/hcsecd/parser.y
index e51f5f882e..031ef2ed53 100644
--- a/usr.sbin/bthcid/parser.y
+++ b/usr.sbin/hcsecd/parser.y
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  * $Id: parser.y,v 1.5 2003/06/07 21:22:30 max Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/hcsecd/parser.y,v 1.4 2004/09/14 20:04:33 emax Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hcsecd/parser.y 235789 2012-05-22 16:33:10Z bapt $
  */
 
 #include <sys/fcntl.h>
@@ -36,26 +36,24 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdio.h>
-#include <stdarg.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <string.h>
 #include <syslog.h>
 #include <unistd.h>
-#include "bthcid.h"
+#include "hcsecd.h"
 
+	int	yyparse  (void);
 	int	yylex    (void);
 
 static	void	free_key (link_key_p key);
 static	int	hexa2int4(char *a);
 static	int	hexa2int8(char *a);
 
-extern	void			 yyerror(const char *);
 extern	int			 yylineno;
-extern	FILE			*yyin;
-
 static	LIST_HEAD(, link_key)	 link_keys;
+	char			*config_file = "/etc/bluetooth/hcsecd.conf";
 
-const	char			*config_file = "/etc/bluetooth/bthcid.conf";
 static	link_key_p		 key = NULL;
 %}
 
@@ -110,7 +108,7 @@ option:		bdaddr
 bdaddr:		T_BDADDR T_BDADDRSTRING
 			{
 			if (!bt_aton($2, &key->bdaddr)) {
-				syslog(LOG_ERR, "Could not parse BD_ADDR " \
+				syslog(LOG_ERR, "Cound not parse BD_ADDR " \
 						"'%s'", $2);
 				exit(1);
 			}
@@ -138,18 +136,18 @@ key:		T_KEY T_HEXSTRING
 			if (key->key != NULL)
 				free(key->key);
 
-			key->key = (uint8_t *) malloc(HCI_KEY_SIZE);
+			key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE);
 			if (key->key == NULL) {
 				syslog(LOG_ERR, "Could not allocate new " \
 						"link key");
 				exit(1);
 			}
 
-			memset(key->key, 0, HCI_KEY_SIZE);
+			memset(key->key, 0, NG_HCI_KEY_SIZE);
 
 			len = strlen($2) / 2;
-			if (len > HCI_KEY_SIZE)
-				len = HCI_KEY_SIZE;
+			if (len > NG_HCI_KEY_SIZE)
+				len = NG_HCI_KEY_SIZE;
 
 			for (i = 0; i < len; i ++)
 				key->key[i] = hexa2int8((char *)($2) + 2*i);
@@ -197,6 +195,8 @@ yyerror(char const *message)
 void
 read_config_file(void)
 {
+	extern FILE	*yyin;
+
 	if (config_file == NULL) {
 		syslog(LOG_ERR, "Unknown config file name!");
 		exit(1);
@@ -226,11 +226,11 @@ read_config_file(void)
 void
 clean_config(void)
 {
-	link_key_p	lkey = NULL;
+	link_key_p	key = NULL;
 
-	while ((lkey = LIST_FIRST(&link_keys)) != NULL) {
-		LIST_REMOVE(lkey, next);
-		free_key(lkey);
+	while ((key = LIST_FIRST(&link_keys)) != NULL) {
+		LIST_REMOVE(key, next);
+		free_key(key);
 	}
 }
 
@@ -238,19 +238,19 @@ clean_config(void)
 link_key_p
 get_key(bdaddr_p bdaddr, int exact_match)
 {
-	link_key_p	lkey = NULL, defkey = NULL;
+	link_key_p	key = NULL, defkey = NULL;
 
-	LIST_FOREACH(lkey, &link_keys, next) {
-		if (memcmp(bdaddr, &lkey->bdaddr, sizeof(lkey->bdaddr)) == 0)
+	LIST_FOREACH(key, &link_keys, next) {
+		if (memcmp(bdaddr, &key->bdaddr, sizeof(key->bdaddr)) == 0)
 			break;
 
 		if (!exact_match)
-			if (memcmp(BDADDR_ANY, &lkey->bdaddr,
-					sizeof(lkey->bdaddr)) == 0)
-				defkey = lkey;
+			if (memcmp(NG_HCI_BDADDR_ANY, &key->bdaddr,
+					sizeof(key->bdaddr)) == 0)
+				defkey = key;
 	}
 
-	return ((lkey != NULL)? lkey : defkey);
+	return ((key != NULL)? key : defkey);
 }
 
 #ifdef __config_debug__
@@ -258,29 +258,29 @@ get_key(bdaddr_p bdaddr, int exact_match)
 void
 dump_config(void)
 {
-	link_key_p	lkey = NULL;
+	link_key_p	key = NULL;
 	char		buffer[64];
 
-	LIST_FOREACH(lkey, &link_keys, next) {
-		if (lkey->key != NULL)
+	LIST_FOREACH(key, &link_keys, next) {
+		if (key->key != NULL)
 			snprintf(buffer, sizeof(buffer),
 "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
-				lkey->key[0], lkey->key[1], lkey->key[2],
-				lkey->key[3], lkey->key[4], lkey->key[5],
-				lkey->key[6], lkey->key[7], lkey->key[8],
-				lkey->key[9], lkey->key[10], lkey->key[11],
-				lkey->key[12], lkey->key[13], lkey->key[14],
-				lkey->key[15]);
+				key->key[0], key->key[1], key->key[2],
+				key->key[3], key->key[4], key->key[5],
+				key->key[6], key->key[7], key->key[8],
+				key->key[9], key->key[10], key->key[11],
+				key->key[12], key->key[13], key->key[14],
+				key->key[15]);
 
 		syslog(LOG_DEBUG, 
 "device %s " \
 "bdaddr %s " \
 "pin %s " \
 "key %s",
-			(lkey->name != NULL)? lkey->name : "noname",
-			bt_ntoa(&lkey->bdaddr, NULL),
-			(lkey->pin != NULL)? lkey->pin : "nopin",
-			(lkey->key != NULL)? buffer : "nokey");
+			(key->name != NULL)? key->name : "noname",
+			bt_ntoa(&key->bdaddr, NULL),
+			(key->pin != NULL)? key->pin : "nopin",
+			(key->key != NULL)? buffer : "nokey");
 	}
 }
 #endif
@@ -290,17 +290,17 @@ int
 read_keys_file(void)
 {
 	FILE		*f = NULL;
-	link_key_t	*lkey = NULL;
-	char		 buf[BTHCID_BUFFER_SIZE], *p = NULL, *cp = NULL;
+	link_key_t	*key = NULL;
+	char		 buf[HCSECD_BUFFER_SIZE], *p = NULL, *cp = NULL;
 	bdaddr_t	 bdaddr;
 	int		 i, len;
 
-	if ((f = fopen(BTHCID_KEYSFILE, "r")) == NULL) {
+	if ((f = fopen(HCSECD_KEYSFILE, "r")) == NULL) {
 		if (errno == ENOENT)
 			return (0);
 
 		syslog(LOG_ERR, "Could not open keys file %s. %s (%d)\n",
-				BTHCID_KEYSFILE, strerror(errno), errno);
+				HCSECD_KEYSFILE, strerror(errno), errno);
 
 		return (-1);
 	}
@@ -316,30 +316,30 @@ read_keys_file(void)
 		if (!bt_aton(p, &bdaddr))
 			continue;
 
-		if ((lkey = get_key(&bdaddr, 1)) == NULL)
+		if ((key = get_key(&bdaddr, 1)) == NULL)
 			continue;
 
-		if (lkey->key == NULL) {
-			lkey->key = (uint8_t *) malloc(HCI_KEY_SIZE);
-			if (lkey->key == NULL) {
+		if (key->key == NULL) {
+			key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE);
+			if (key->key == NULL) {
 				syslog(LOG_ERR, "Could not allocate link key");
 				exit(1);
 			}
 		}
 
-		memset(lkey->key, 0, HCI_KEY_SIZE);
+		memset(key->key, 0, NG_HCI_KEY_SIZE);
 
 		len = strlen(cp) / 2;
-		if (len > HCI_KEY_SIZE)
-			len = HCI_KEY_SIZE;
+		if (len > NG_HCI_KEY_SIZE)
+			len = NG_HCI_KEY_SIZE;
 
 		for (i = 0; i < len; i ++)
-			lkey->key[i] = hexa2int8(cp + 2*i);
+			key->key[i] = hexa2int8(cp + 2*i);
 
 		syslog(LOG_DEBUG, "Restored link key for the entry, " \
 				"remote bdaddr %s, name '%s'",
-				bt_ntoa(&lkey->bdaddr, NULL),
-				(lkey->name != NULL)? lkey->name : "No name");
+				bt_ntoa(&key->bdaddr, NULL),
+				(key->name != NULL)? key->name : "No name");
 	}
 
 	fclose(f);
@@ -351,28 +351,28 @@ read_keys_file(void)
 int
 dump_keys_file(void)
 {
-	link_key_p	lkey = NULL;
-	char		tmp[PATH_MAX], buf[BTHCID_BUFFER_SIZE];
+	link_key_p	key = NULL;
+	char		tmp[PATH_MAX], buf[HCSECD_BUFFER_SIZE];
 	int		f;
 
-	snprintf(tmp, sizeof(tmp), "%s.tmp", BTHCID_KEYSFILE);
+	snprintf(tmp, sizeof(tmp), "%s.tmp", HCSECD_KEYSFILE);
 	if ((f = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600)) < 0) {
 		syslog(LOG_ERR, "Could not create temp keys file %s. %s (%d)\n",
 				tmp, strerror(errno), errno);
 		return (-1);
 	}
 
-	LIST_FOREACH(lkey, &link_keys, next) {
-		if (lkey->key == NULL)
+	LIST_FOREACH(key, &link_keys, next) {
+		if (key->key == NULL)
 			continue;
 
 		snprintf(buf, sizeof(buf),
 "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
-			bt_ntoa(&lkey->bdaddr, NULL),
-			lkey->key[0],  lkey->key[1],  lkey->key[2],  lkey->key[3],
-			lkey->key[4],  lkey->key[5],  lkey->key[6],  lkey->key[7],
-			lkey->key[8],  lkey->key[9],  lkey->key[10], lkey->key[11],
-			lkey->key[12], lkey->key[13], lkey->key[14], lkey->key[15]);
+			bt_ntoa(&key->bdaddr, NULL),
+			key->key[0],  key->key[1],  key->key[2],  key->key[3],
+			key->key[4],  key->key[5],  key->key[6],  key->key[7],
+			key->key[8],  key->key[9],  key->key[10], key->key[11],
+			key->key[12], key->key[13], key->key[14], key->key[15]);
 
 		if (write(f, buf, strlen(buf)) < 0) {
 			syslog(LOG_ERR, "Could not write temp keys file. " \
@@ -383,9 +383,9 @@ dump_keys_file(void)
 
 	close(f);
 
-	if (rename(tmp, BTHCID_KEYSFILE) < 0) {
+	if (rename(tmp, HCSECD_KEYSFILE) < 0) {
 		syslog(LOG_ERR, "Could not rename(%s, %s). %s (%d)\n",
-				tmp, BTHCID_KEYSFILE, strerror(errno), errno);
+				tmp, HCSECD_KEYSFILE, strerror(errno), errno);
 		unlink(tmp);
 		return (-1);
 	}
@@ -395,17 +395,17 @@ dump_keys_file(void)
 
 /* Free key entry */
 static void
-free_key(link_key_p lkey)
+free_key(link_key_p key)
 {
-	if (lkey->name != NULL)
-		free(lkey->name);
-	if (lkey->key != NULL)
-		free(lkey->key);
-	if (lkey->pin != NULL)
-		free(lkey->pin);
-
-	memset(lkey, 0, sizeof(*lkey));
-	free(lkey);
+	if (key->name != NULL)
+		free(key->name);
+	if (key->key != NULL)
+		free(key->key);
+	if (key->pin != NULL)
+		free(key->pin);
+
+	memset(key, 0, sizeof(*key));
+	free(key);
 }
 
 /* Convert hex ASCII to int4 */
diff --git a/usr.sbin/hcseriald/Makefile b/usr.sbin/hcseriald/Makefile
new file mode 100644
index 0000000000..295f85f2da
--- /dev/null
+++ b/usr.sbin/hcseriald/Makefile
@@ -0,0 +1,11 @@
+# $Id: Makefile,v 1.5 2003/08/14 20:06:21 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/hcseriald/Makefile 140941 2005-01-28 16:08:11Z ru $
+
+PROG=		hcseriald
+MAN=		hcseriald.8
+WARNS?=		2
+
+DPADD=		${LIBNETGRAPH}
+LDADD=		-lnetgraph
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/hcseriald/hcseriald.8 b/usr.sbin/hcseriald/hcseriald.8
new file mode 100644
index 0000000000..d033f1dfee
--- /dev/null
+++ b/usr.sbin/hcseriald/hcseriald.8
@@ -0,0 +1,86 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: hcseriald.8,v 1.3 2003/05/21 00:47:26 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/hcseriald/hcseriald.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd June 14, 2002
+.Dt HCSERIALD 8
+.Os
+.Sh NAME
+.Nm hcseriald
+.Nd supervise serial Bluetooth devices
+.Sh SYNOPSIS
+.Nm
+.Op Fl dh
+.Fl f Ar device
+.Fl n Ar node_name
+.Op Fl s Ar speed
+.Sh DESCRIPTION
+The
+.Nm
+utility handles serial Bluetooth devices.
+It does one simple thing:
+it opens the specified serial device, sets the device parameters, and pushes
+the
+.Dv H4
+line discipline.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl d
+Do not disassociate from the controlling terminal, i.e., run in foreground.
+.It Fl f Ar device
+Callout device name.
+Example:
+.Fl f Pa /dev/cuau0 .
+.It Fl h
+Display usage message and exit.
+.It Fl n Ar node_name
+Set H4 Netgraph node name.
+Example:
+.Fl n Li sio0 .
+.It Fl s Ar speed
+Set serial device speed to
+.Ar speed .
+Example:
+.Fl s Li 115200 .
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /var/run/hcserial. Ns Ar * Ns Pa .pid" -compact
+.It Pa /var/run/hcserial. Ns Ar * Ns Pa .pid
+Process ID of the currently running
+.Nm
+daemon.
+Where
+.Ar *
+is an H4 Netgraph node name.
+.El
+.Sh SEE ALSO
+.Xr ng_h4 4 ,
+.Xr ng_hci 4 ,
+.Xr tty 4 ,
+.Xr hccontrol 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
diff --git a/usr.sbin/hcseriald/hcseriald.c b/usr.sbin/hcseriald/hcseriald.c
new file mode 100644
index 0000000000..c2a6566705
--- /dev/null
+++ b/usr.sbin/hcseriald/hcseriald.c
@@ -0,0 +1,268 @@
+/*
+ * hcseriald.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: hcseriald.c,v 1.3 2003/05/21 22:40:32 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/hcseriald/hcseriald.c 244040 2012-12-08 22:16:36Z eadler $
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <netgraph7/ng_message.h>
+#include <netgraph.h>
+#include <netgraph7/bluetooth/include/ng_h4.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> 
+#include <syslog.h>
+#include <termios.h>
+#include <unistd.h>
+
+/* Prototypes */
+static int	open_device	(char const *, speed_t, char const *);
+static void	sighandler	(int);
+static void	usage		();
+
+static char const * const	hcseriald = "hcseriald";
+static int			done = 0;
+
+int
+main(int argc, char *argv[])
+{
+	char			*device = NULL, *name = NULL;
+	speed_t			 speed = 115200;
+	int			 n, detach = 1;
+	char			 p[FILENAME_MAX];
+	FILE			*f = NULL;
+	struct sigaction	 sa;
+
+	/* Process command line arguments */
+	while ((n = getopt(argc, argv, "df:n:s:h")) != -1) {
+		switch (n) {
+		case 'd':
+			detach = 0;
+			break;
+
+		case 'f':
+			device = optarg;
+			break;
+
+		case 'n':
+			name = optarg;
+			break;
+
+		case 's':
+			speed = atoi(optarg);
+			if (speed < 0)
+				usage(argv[0]);
+			break;
+
+		case 'h':
+		default:
+			usage(argv[0]);
+			break;
+		}
+	}
+
+	if (device == NULL || name == NULL)
+		usage(argv[0]);
+
+	openlog(hcseriald, LOG_PID | LOG_NDELAY, LOG_USER);
+
+	/* Open device */
+	n = open_device(device, speed, name);
+
+	if (detach && daemon(0, 0) < 0) {
+		syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	/* Write PID file */
+	snprintf(p, sizeof(p), "/var/run/%s.%s.pid", hcseriald, name);
+	f = fopen(p, "w");
+	if (f == NULL) {
+		syslog(LOG_ERR, "Could not fopen(%s). %s (%d)",
+			p, strerror(errno), errno);
+		exit(1);
+	}
+	fprintf(f, "%d", getpid());
+	fclose(f);
+
+	/* Install signal handler */
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = sighandler;
+
+	if (sigaction(SIGTERM, &sa, NULL) < 0) {
+		syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	if (sigaction(SIGHUP, &sa, NULL) < 0) {
+		syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	if (sigaction(SIGINT, &sa, NULL) < 0) {
+		syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	/* Keep running */
+	while (!done)
+		select(0, NULL, NULL, NULL, NULL);
+
+	/* Remove PID file and close device */
+	unlink(p);
+	close(n);
+	closelog();
+
+	return (0);
+} /* main */
+
+/* Open terminal, set settings, push H4 line discipline and set node name */
+static int
+open_device(char const *device, speed_t speed, char const *name)
+{
+	int		fd, disc, cs, ds;
+	struct termios	t;
+	struct nodeinfo	ni;
+	struct ngm_name	n;
+	char		p[NG_NODESIZ];
+
+	/* Open terminal device and setup H4 line discipline */
+	fd = open(device, O_RDWR|O_NOCTTY);
+	if (fd < 0) {
+		syslog(LOG_ERR, "Could not open(%s). %s (%d)", 
+			device, strerror(errno), errno);
+		exit(1);
+	}
+
+	tcflush(fd, TCIOFLUSH);
+
+	if (tcgetattr(fd, &t) < 0) {
+		syslog(LOG_ERR, "Could not tcgetattr(%s). %s (%d)",
+			device, strerror(errno), errno);
+		exit(1);
+	}
+
+	cfmakeraw(&t);
+
+	t.c_cflag |= CLOCAL;	/* clocal */
+	t.c_cflag &= ~CSIZE;	/* cs8 */
+	t.c_cflag |= CS8; 	/* cs8 */
+	t.c_cflag &= ~PARENB;	/* -parenb */
+	t.c_cflag &= ~CSTOPB;	/* -cstopb */
+	t.c_cflag |= CRTSCTS;	/* crtscts */
+
+	if (tcsetattr(fd, TCSANOW, &t) < 0) {
+		syslog(LOG_ERR, "Could not tcsetattr(%s). %s (%d)",
+			device, strerror(errno), errno);
+		exit(1);
+	}
+
+	tcflush(fd, TCIOFLUSH);
+
+	if (cfsetspeed(&t, speed) < 0) {
+		syslog(LOG_ERR, "Could not cfsetspeed(%s). %s (%d)",
+			device, strerror(errno), errno);
+		exit(1);
+	}
+
+	if (tcsetattr(fd, TCSANOW, &t) < 0) {
+		syslog(LOG_ERR, "Could not tcsetattr(%s). %s (%d)",
+			device, strerror(errno), errno);
+		exit(1);
+	}
+
+	disc = BTUARTDISC;
+	if (ioctl(fd, TIOCSETD, &disc) < 0) {
+		syslog(LOG_ERR, "Could not ioctl(%s, TIOCSETD, %d). %s (%d)",
+			device, disc, strerror(errno), errno);
+		exit(1);
+	}
+
+	/* Get default name of the Netgraph node */
+	memset(&ni, 0, sizeof(ni));
+	if (ioctl(fd, NGIOCGINFO, &ni) < 0) {
+		syslog(LOG_ERR, "Could not ioctl(%d, NGIOGINFO). %s (%d)",
+			fd, strerror(errno), errno);
+		exit(1);
+	}
+
+	/* Assign new name to the Netgraph node */
+	snprintf(p, sizeof(p), "%s:", ni.name);
+	snprintf(n.name, sizeof(n.name), "%s", name);
+
+	if (NgMkSockNode(NULL, &cs, &ds) < 0) {
+		syslog(LOG_ERR, "Could not NgMkSockNode(). %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	if (NgSendMsg(cs, p, NGM_GENERIC_COOKIE, NGM_NAME, &n, sizeof(n)) < 0) {
+		syslog(LOG_ERR, "Could not NgSendMsg(%d, %s, NGM_NAME, %s). " \
+			"%s (%d)", cs, p, n.name, strerror(errno), errno);
+		exit(1);
+	}
+
+	close(cs);
+	close(ds);
+
+	return (fd);
+} /* open_device */
+
+/* Signal handler */
+static void
+sighandler(int s)
+{
+	done = 1;
+} /* sighandler */
+
+/* Usage */
+static void
+usage(void)
+{
+	fprintf(stderr, "Usage: %s -f device -n node_name [-s speed -d -h]\n" \
+			"Where:\n" \
+			"\t-f device    tty device name, ex. /dev/cuau1\n" \
+			"\t-n node_name set Netgraph node name to node_name\n" \
+			"\t-s speed     set tty speed, ex. 115200\n" \
+			"\t-d           run in foreground\n" \
+			"\t-h           display this message\n",
+			hcseriald);
+	exit(255);
+} /* usage */
+
diff --git a/usr.sbin/l2control/Makefile b/usr.sbin/l2control/Makefile
new file mode 100644
index 0000000000..1125803f24
--- /dev/null
+++ b/usr.sbin/l2control/Makefile
@@ -0,0 +1,12 @@
+# $Id: Makefile,v 1.7 2003/08/14 20:06:22 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/l2control/Makefile 121054 2003-10-12 22:04:24Z emax $
+
+PROG=		l2control
+MAN=		l2control.8
+SRCS=		l2cap.c l2control.c
+WARNS?=		2
+
+DPADD=		${LIBBLUETOOTH}
+LDADD=		-lbluetooth
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/l2control/l2cap.c b/usr.sbin/l2control/l2cap.c
new file mode 100644
index 0000000000..155f6a29e0
--- /dev/null
+++ b/usr.sbin/l2control/l2cap.c
@@ -0,0 +1,313 @@
+/*
+ * l2cap.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: l2cap.c,v 1.5 2003/05/16 19:52:37 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/l2control/l2cap.c 121054 2003-10-12 22:04:24Z emax $
+ */
+
+#include <sys/ioctl.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "l2control.h"
+
+#define	SIZE(x)	(sizeof((x))/sizeof((x)[0]))
+
+/* Print BDADDR */
+static char *
+bdaddrpr(bdaddr_t const *ba)
+{
+	extern int	 numeric_bdaddr;
+	static char	 str[24];
+	struct hostent	*he = NULL;
+
+	if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
+		str[0] = '*';
+		str[1] = 0;
+
+		return (str);
+	}
+
+	if (!numeric_bdaddr &&
+	    (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
+		strlcpy(str, he->h_name, sizeof(str));
+
+		return (str);
+	}
+
+	bt_ntoa(ba, str);
+
+	return (str);
+} /* bdaddrpr */
+
+/* Send read_node_flags command to the node */
+static int
+l2cap_read_node_flags(int s, int argc, char **argv)
+{
+	struct ng_btsocket_l2cap_raw_node_flags	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_L2CAP_NODE_GET_FLAGS, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "Connectionless traffic flags:\n");
+	fprintf(stdout, "\tSDP: %s\n",
+		(r.flags & NG_L2CAP_CLT_SDP_DISABLED)? "disabled" : "enabled");
+	fprintf(stdout, "\tRFCOMM: %s\n",
+		(r.flags & NG_L2CAP_CLT_RFCOMM_DISABLED)? "disabled":"enabled");
+	fprintf(stdout, "\tTCP: %s\n",
+		(r.flags & NG_L2CAP_CLT_TCP_DISABLED)? "disabled" : "enabled");
+
+	return (OK);
+} /* l2cap_read_node_flags */
+
+/* Send read_debug_level command to the node */
+static int
+l2cap_read_debug_level(int s, int argc, char **argv)
+{
+	struct ng_btsocket_l2cap_raw_node_debug	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_L2CAP_NODE_GET_DEBUG, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	fprintf(stdout, "Debug level: %d\n", r.debug);
+
+	return (OK);
+} /* l2cap_read_debug_level */
+
+/* Send write_debug_level command to the node */
+static int
+l2cap_write_debug_level(int s, int argc, char **argv)
+{
+	struct ng_btsocket_l2cap_raw_node_debug	r;
+
+	memset(&r, 0, sizeof(r));
+	switch (argc) {
+	case 1:
+		r.debug = atoi(argv[0]);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	if (ioctl(s, SIOC_L2CAP_NODE_SET_DEBUG, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	return (OK);
+} /* l2cap_write_debug_level */
+
+/* Send read_connection_list command to the node */
+static int
+l2cap_read_connection_list(int s, int argc, char **argv)
+{
+	static char const * const	state[] = {
+		/* NG_L2CAP_CON_CLOSED */	"CLOSED",
+		/* NG_L2CAP_W4_LP_CON_CFM */	"W4_LP_CON_CFM",
+		/* NG_L2CAP_CON_OPEN */		"OPEN"
+	};
+#define con_state2str(x)	((x) >= SIZE(state)? "UNKNOWN" : state[(x)])
+
+	struct ng_btsocket_l2cap_raw_con_list	r;
+	int					n, error = OK;
+
+	memset(&r, 0, sizeof(r));
+	r.num_connections = NG_L2CAP_MAX_CON_NUM;
+	r.connections = calloc(NG_L2CAP_MAX_CON_NUM,
+				sizeof(ng_l2cap_node_con_ep));
+	if (r.connections == NULL) {
+		errno = ENOMEM;
+		return (ERROR);
+	}
+
+	if (ioctl(s, SIOC_L2CAP_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) {
+		error = ERROR;
+		goto out;
+	}
+
+	fprintf(stdout, "L2CAP connections:\n");
+	fprintf(stdout, 
+"Remote BD_ADDR    Handle Flags Pending State\n");
+	for (n = 0; n < r.num_connections; n++) {
+		fprintf(stdout,
+			"%-17.17s " \
+			"%6d " \
+			"%c%c%c%c%c " \
+			"%7d " \
+			"%s\n",
+			bdaddrpr(&r.connections[n].remote),
+			r.connections[n].con_handle, 
+			((r.connections[n].flags & NG_L2CAP_CON_OUTGOING)? 'O' : 'I'),
+			((r.connections[n].flags & NG_L2CAP_CON_LP_TIMO)? 'L' : ' '),
+			((r.connections[n].flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)? 'D' : ' '),
+			((r.connections[n].flags & NG_L2CAP_CON_TX)? 'T' : ' '),
+			((r.connections[n].flags & NG_L2CAP_CON_RX)? 'R' : ' '),
+			r.connections[n].pending,
+			con_state2str(r.connections[n].state));
+	}
+out:
+	free(r.connections);
+
+	return (error);
+} /* l2cap_read_connection_list */
+
+/* Send read_channel_list command to the node */
+static int
+l2cap_read_channel_list(int s, int argc, char **argv)
+{
+	static char const * const	state[] = {
+		/* NG_L2CAP_CLOSED */			"CLOSED",
+		/* NG_L2CAP_W4_L2CAP_CON_RSP */		"W4_L2CAP_CON_RSP",
+		/* NG_L2CAP_W4_L2CA_CON_RSP */		"W4_L2CA_CON_RSP",
+		/* NG_L2CAP_CONFIG */			"CONFIG",
+		/* NG_L2CAP_OPEN */			"OPEN",
+		/* NG_L2CAP_W4_L2CAP_DISCON_RSP */	"W4_L2CAP_DISCON_RSP",
+		/* NG_L2CAP_W4_L2CA_DISCON_RSP */	"W4_L2CA_DISCON_RSP"
+	};
+#define ch_state2str(x)	((x) >= SIZE(state)? "UNKNOWN" : state[(x)])
+
+	struct ng_btsocket_l2cap_raw_chan_list	r;
+	int					n, error = OK;
+
+	memset(&r, 0, sizeof(r));
+	r.num_channels = NG_L2CAP_MAX_CHAN_NUM;
+	r.channels = calloc(NG_L2CAP_MAX_CHAN_NUM,
+				sizeof(ng_l2cap_node_chan_ep));
+	if (r.channels == NULL) {
+		errno = ENOMEM;
+		return (ERROR);
+	}
+
+	if (ioctl(s, SIOC_L2CAP_NODE_GET_CHAN_LIST, &r, sizeof(r)) < 0) {
+		error = ERROR;
+		goto out;
+	}
+
+	fprintf(stdout, "L2CAP channels:\n");
+	fprintf(stdout, 
+"Remote BD_ADDR     SCID/ DCID   PSM  IMTU/ OMTU State\n");
+	for (n = 0; n < r.num_channels; n++) {
+		fprintf(stdout,
+			"%-17.17s " \
+			"%5d/%5d %5d " \
+			"%5d/%5d " \
+			"%s\n",
+			bdaddrpr(&r.channels[n].remote),
+			r.channels[n].scid, r.channels[n].dcid,
+			r.channels[n].psm, r.channels[n].imtu,
+			r.channels[n].omtu,
+			ch_state2str(r.channels[n].state));
+	}
+out:
+	free(r.channels);
+
+	return (error);
+} /* l2cap_read_channel_list */
+
+/* Send read_auto_disconnect_timeout command to the node */
+static int
+l2cap_read_auto_disconnect_timeout(int s, int argc, char **argv)
+{
+	struct ng_btsocket_l2cap_raw_auto_discon_timo	r;
+
+	memset(&r, 0, sizeof(r));
+	if (ioctl(s, SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	if (r.timeout != 0)
+		fprintf(stdout, "Auto disconnect timeout: %d sec\n", r.timeout);
+	else
+		fprintf(stdout, "Auto disconnect disabled\n");
+
+	return (OK);
+} /* l2cap_read_auto_disconnect_timeout */
+
+/* Send write_auto_disconnect_timeout command to the node */
+static int
+l2cap_write_auto_disconnect_timeout(int s, int argc, char **argv)
+{
+	struct ng_btsocket_l2cap_raw_auto_discon_timo	r;
+
+	memset(&r, 0, sizeof(r));
+	switch (argc) {
+	case 1:
+		r.timeout = atoi(argv[0]);
+		break;
+
+	default:
+		return (USAGE);
+	}
+
+	if (ioctl(s, SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO, &r, sizeof(r)) < 0)
+		return (ERROR);
+
+	return (OK);
+} /* l2cap_write_auto_disconnect_timeout */
+
+struct l2cap_command	l2cap_commands[] = {
+{
+"read_node_flags",
+"Get L2CAP node flags",
+&l2cap_read_node_flags
+},
+{
+"read_debug_level",
+"Get L2CAP node debug level",
+&l2cap_read_debug_level
+},
+{
+"write_debug_level <level>",
+"Set L2CAP node debug level",
+&l2cap_write_debug_level
+},
+{
+"read_connection_list",
+"Read list of the L2CAP connections",
+&l2cap_read_connection_list
+},
+{
+"read_channel_list",
+"Read list of the L2CAP channels",
+&l2cap_read_channel_list
+},
+{
+"read_auto_disconnect_timeout",
+"Get L2CAP node auto disconnect timeout (in sec)",
+&l2cap_read_auto_disconnect_timeout
+},
+{
+"write_auto_disconnect_timeout <timeout>",
+"Set L2CAP node auto disconnect timeout (in sec)",
+&l2cap_write_auto_disconnect_timeout
+},
+{
+NULL,
+}};
+
diff --git a/usr.sbin/l2control/l2control.8 b/usr.sbin/l2control/l2control.8
new file mode 100644
index 0000000000..58a1c229e0
--- /dev/null
+++ b/usr.sbin/l2control/l2control.8
@@ -0,0 +1,97 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: l2control.8,v 1.5 2003/05/21 00:53:00 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/l2control/l2control.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd April 9, 2011
+.Dt L2CONTROL 8
+.Os
+.Sh NAME
+.Nm l2control
+.Nd L2CAP configuration utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl hn
+.Fl a Ar local
+.Ar command
+.Op Ar parameters ...
+.Sh DESCRIPTION
+The
+.Nm
+utility connects to the local device with the specified BD_ADDR or name
+and attempts to send the specified command.
+The
+.Nm
+utility will print results to the standard output and error messages to
+the standard error output.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar local
+Connect to the local device with the specified BD_ADDR or name.
+Example:
+.Fl a Li 00:01:02:03:04:05
+or
+.Fl a Li bt_device .
+.It Fl h
+Display usage message and exit.
+.It Fl n
+Show Bluetooth addresses as numbers.
+Normally
+.Nm
+attempts to resolve Bluetooth addresses, and display them symbolically.
+.It Ar command
+One of the supported commands (see below).
+The special command
+.Cm help
+can be used to obtain a list of all supported commands.
+To get more information about a specific command use
+.Cm help Ar command .
+.It Ar parameters
+One or more optional space separated command parameters.
+.El
+.Sh COMMANDS
+The currently supported node commands in
+.Nm
+are:
+.Pp
+.Bl -tag -width "Write_Auto_Disconnect_Timeout" -offset indent -compact
+.It Cm Read_Node_Flags
+.It Cm Read_Debug_Level
+.It Cm Write_Debug_Level
+.It Cm Read_Connection_List
+.It Cm Read_Channel_List
+.It Cm Read_Auto_Disconnect_Timeout
+.It Cm Write_Auto_Disconnect_Timeout
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr netgraph 3 ,
+.Xr netgraph 4 ,
+.Xr ng_l2cap 4 ,
+.Xr l2ping 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt emax@FreeBSD.org
diff --git a/usr.sbin/l2control/l2control.c b/usr.sbin/l2control/l2control.c
new file mode 100644
index 0000000000..7405cf67d7
--- /dev/null
+++ b/usr.sbin/l2control/l2control.c
@@ -0,0 +1,220 @@
+/*
+ * l2control.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: l2control.c,v 1.6 2003/09/05 00:38:25 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/l2control/l2control.c 220840 2011-04-19 16:21:57Z emax $
+ */
+
+#include <assert.h>
+#include <bluetooth.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "l2control.h"
+
+/* Prototypes */
+static int                    do_l2cap_command    (bdaddr_p, int, char **);
+static struct l2cap_command * find_l2cap_command  (char const *, 
+                                                   struct l2cap_command *);
+static void                   print_l2cap_command (struct l2cap_command *);
+static void                   usage               (void);
+
+/* Main */
+
+int	numeric_bdaddr = 0;
+
+int
+main(int argc, char *argv[])
+{
+	int		n;
+	bdaddr_t	bdaddr;
+
+	memset(&bdaddr, 0, sizeof(bdaddr));
+
+	/* Process command line arguments */
+	while ((n = getopt(argc, argv, "a:nh")) != -1) {
+		switch (n) {
+		case 'a':
+			if (!bt_aton(optarg, &bdaddr)) {
+				struct hostent	*he = NULL;
+
+				if ((he = bt_gethostbyname(optarg)) == NULL)
+					errx(1, "%s: %s", optarg, hstrerror(h_errno));
+
+				memcpy(&bdaddr, he->h_addr, sizeof(bdaddr));
+			}
+			break;
+
+		case 'n':
+			numeric_bdaddr = 1;
+			break;
+
+		case 'h':
+		default:
+			usage();
+			break;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (*argv == NULL)
+		usage();
+
+	return (do_l2cap_command(&bdaddr, argc, argv));
+} /* main */
+
+/* Execute commands */
+static int
+do_l2cap_command(bdaddr_p bdaddr, int argc, char **argv)
+{
+	char			*cmd = argv[0];
+	struct l2cap_command	*c = NULL;
+	struct sockaddr_l2cap	 sa;
+	int			 s, e, help;
+
+	help = 0;
+	if (strcasecmp(cmd, "help") == 0) {
+		argc --;
+		argv ++;
+
+		if (argc <= 0) {
+			fprintf(stdout, "Supported commands:\n");
+			print_l2cap_command(l2cap_commands);
+			fprintf(stdout, "\nFor more information use " \
+				"'help command'\n");
+
+			return (OK);
+		}
+
+		help = 1;
+		cmd = argv[0];
+	}
+
+	c = find_l2cap_command(cmd, l2cap_commands);
+	if (c == NULL) {
+		fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
+		return (ERROR);
+	}
+
+	if (!help) {
+		if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0)
+			usage();
+
+		memset(&sa, 0, sizeof(sa));
+		sa.l2cap_len = sizeof(sa);
+		sa.l2cap_family = AF_BLUETOOTH;
+		memcpy(&sa.l2cap_bdaddr, bdaddr, sizeof(sa.l2cap_bdaddr));
+
+		s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_L2CAP);
+		if (s < 0)
+			err(1, "Could not create socket");
+	
+		if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+			err(2,
+"Could not bind socket, bdaddr=%s", bt_ntoa(&sa.l2cap_bdaddr, NULL));
+
+		e = 0x0ffff;
+		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &e, sizeof(e)) < 0)
+			err(3, "Coult not setsockopt(RCVBUF, %d)", e);
+
+		e = (c->handler)(s, -- argc, ++ argv);
+
+		close(s);
+	} else
+		e = USAGE;
+
+	switch (e) {
+	case OK:
+	case FAILED:
+		break;
+
+	case ERROR:
+		fprintf(stdout, "Could not execute command \"%s\". %s\n",
+			cmd, strerror(errno));
+		break;
+
+	case USAGE:
+		fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
+		break;
+
+	default: assert(0); break;
+	}
+
+	return (e);
+} /* do_l2cap_command */
+
+/* Try to find command in specified category */
+static struct l2cap_command *
+find_l2cap_command(char const *command, struct l2cap_command *category)
+{
+	struct l2cap_command	*c = NULL;
+
+	for (c = category; c->command != NULL; c++) {
+		char 	*c_end = strchr(c->command, ' ');
+
+		if (c_end != NULL) {
+			int	len = c_end - c->command;
+
+			if (strncasecmp(command, c->command, len) == 0)
+				return (c);
+		} else if (strcasecmp(command, c->command) == 0)
+				return (c);
+	}
+
+	return (NULL);
+} /* find_l2cap_command */
+
+/* Print commands in specified category */
+static void
+print_l2cap_command(struct l2cap_command *category)
+{
+	struct l2cap_command	*c = NULL;
+
+	for (c = category; c->command != NULL; c++)
+		fprintf(stdout, "\t%s\n", c->command);
+} /* print_l2cap_command */
+
+/* Usage */
+static void
+usage(void)
+{
+	fprintf(stderr, "Usage: l2control [-hn] -a local cmd [params ..]\n");
+	fprintf(stderr, "Where:\n");
+	fprintf(stderr, "  -a local   Specify local device to connect to\n");
+	fprintf(stderr, "  -h         Display this message\n");
+	fprintf(stderr, "  -n         Show addresses as numbers\n");
+	fprintf(stderr, "  cmd        Supported command " \
+		"(see l2control help)\n");
+	fprintf(stderr, "  params     Optional command parameters\n");
+	exit(255);
+} /* usage */
+
diff --git a/usr.sbin/l2control/l2control.h b/usr.sbin/l2control/l2control.h
new file mode 100644
index 0000000000..600e206039
--- /dev/null
+++ b/usr.sbin/l2control/l2control.h
@@ -0,0 +1,49 @@
+/*
+ * l2control.h
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: l2control.h,v 1.1 2002/11/24 20:22:41 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/l2control/l2control.h 114879 2003-05-10 21:50:37Z julian $
+ */
+
+#ifndef _L2CONTROL_H_
+#define _L2CONTROL_H_
+
+#define	OK			0	/* everything was OK */
+#define	ERROR			1	/* could not execute command */
+#define	FAILED			2	/* error was reported */
+#define	USAGE			3	/* invalid parameters */
+
+struct l2cap_command {
+	char const		*command;
+	char const		*description;
+	int			(*handler)(int, int, char **);
+};
+
+extern struct l2cap_command	 l2cap_commands[];
+
+#endif /* _L2CONTROL_H_ */
+
diff --git a/usr.sbin/l2ping/Makefile b/usr.sbin/l2ping/Makefile
new file mode 100644
index 0000000000..6ff2635d84
--- /dev/null
+++ b/usr.sbin/l2ping/Makefile
@@ -0,0 +1,11 @@
+# $Id: Makefile,v 1.6 2003/08/14 20:06:24 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/l2ping/Makefile 140941 2005-01-28 16:08:11Z ru $
+
+PROG=		l2ping
+MAN=		l2ping.8
+WARNS?=		2
+
+DPADD=		${LIBBLUETOOTH}
+LDADD=		-lbluetooth
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/l2ping/l2ping.8 b/usr.sbin/l2ping/l2ping.8
new file mode 100644
index 0000000000..1c17afde3a
--- /dev/null
+++ b/usr.sbin/l2ping/l2ping.8
@@ -0,0 +1,114 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: l2ping.8,v 1.3 2003/05/21 01:00:19 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/l2ping/l2ping.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd March 29, 2011
+.Dt L2PING 8
+.Os
+.Sh NAME
+.Nm l2ping
+.Nd send L2CAP ECHO_REQUEST to remote devices
+.Sh SYNOPSIS
+.Nm
+.Op Fl fhn
+.Fl a Ar remote
+.Op Fl c Ar count
+.Op Fl i Ar wait
+.Op Fl S Ar source
+.Op Fl s Ar size
+.Sh DESCRIPTION
+The
+.Nm
+utility uses L2CAP
+.Dv ECHO_REQUEST
+datagram to elicit an L2CAP
+.Dv ECHO_RESPONSE
+datagram from a remote device.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar remote
+Specify the remote device to ping.
+The remote device can be specified by either its BD_ADDR or name.
+If name was specified then the
+.Nm
+utility will attempt to resolve the name via
+.Xr bt_gethostbyname 3 .
+.It Fl c Ar count
+Number of packets to send.
+If this option is not specified,
+.Nm
+will operate until interrupted.
+.It Fl f
+Do not wait between sending each packet.
+.It Fl h
+Display usage message and exit.
+.It Fl i Ar wait
+Wait
+.Ar wait
+seconds between sending each packet.
+The default is to wait for one second between each packet.
+This option is ignored if
+.Fl f
+has been specified.
+.It Fl n
+Numeric output only.
+No attempt will be made to look up symbolic names for host addresses.
+.It Fl S Ar source
+Specify the local device which should be used to send L2CAP
+.Dv ECHO_REQUEST
+datagrams.
+The local device can be specified by either its BD_ADDR or name.
+If name was specified then the
+.Nm
+utility will attempt to resolve the name via
+.Xr bt_gethostbyname 3 .
+.It Fl s Ar size
+Specify the number of payload bytes to be sent.
+The default size is 44 bytes.
+It is calculated as minimum L2CAP MTU (48 bytes) minus the size of the L2CAP
+signalling command header (4 bytes).
+The maximum size is 65531 bytes.
+Is is calculated as maximum L2CAP MTU
+(65535 bytes) minus four bytes of payload reserved for
+.Nm
+internal use.
+Use this option with caution.
+Some implementations may not like large sizes and may hang or even crash.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr bluetooth 3 ,
+.Xr netgraph 3 ,
+.Xr netgraph 4 ,
+.Xr ng_l2cap 4 ,
+.Xr l2control 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt emax@FreeBSD.org
+.Sh BUGS
+Could collect more statistic.
+Could check for duplicated, corrupted and lost packets.
diff --git a/usr.sbin/l2ping/l2ping.c b/usr.sbin/l2ping/l2ping.c
new file mode 100644
index 0000000000..0b4ebdb375
--- /dev/null
+++ b/usr.sbin/l2ping/l2ping.c
@@ -0,0 +1,292 @@
+/*
+ * l2ping.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: l2ping.c,v 1.5 2003/05/16 19:54:40 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/l2ping/l2ping.c 220116 2011-03-28 23:08:18Z emax $
+ */
+
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void	usage	(void);
+static void	tv_sub	(struct timeval *, struct timeval const *);
+static double	tv2msec	(struct timeval const *);
+
+#undef	min
+#define	min(x, y)	(((x) > (y))? (y) : (x))
+
+static char const		pattern[] = "1234567890-";
+#define PATTERN_SIZE		(sizeof(pattern) - 1)
+
+/* 
+ * Main 
+ */
+
+int
+main(int argc, char *argv[])
+{
+	bdaddr_t		 src, dst;
+	struct hostent		*he;
+	uint8_t			*echo_data;
+	struct sockaddr_l2cap	 sa;
+	int32_t			 n, s, count, wait, flood, echo_size, numeric;
+	char			*endp, *rname;
+
+	/* Set defaults */
+	memcpy(&src, NG_HCI_BDADDR_ANY, sizeof(src));
+	memcpy(&dst, NG_HCI_BDADDR_ANY, sizeof(dst));
+
+	echo_data = (uint8_t *) calloc(NG_L2CAP_MAX_ECHO_SIZE, sizeof(uint8_t));
+	if (echo_data == NULL) {
+		fprintf(stderr, "Failed to allocate echo data buffer");
+		exit(1);
+	}
+
+	/*
+	 * Set default echo size to the NG_L2CAP_MTU_MINIMUM minus
+	 * the size of the L2CAP signalling command header.
+	 */
+
+	echo_size = NG_L2CAP_MTU_MINIMUM - sizeof(ng_l2cap_cmd_hdr_t);
+	count = -1; /* unimited */
+	wait = 1;   /* sec */
+	flood = 0;
+	numeric = 0;
+
+	/* Parse command line arguments */
+	while ((n = getopt(argc, argv, "a:c:fi:nS:s:h")) != -1) {
+		switch (n) {
+		case 'a':
+			if (!bt_aton(optarg, &dst)) {
+				if ((he = bt_gethostbyname(optarg)) == NULL)
+					errx(1, "%s: %s", optarg, hstrerror(h_errno));
+
+				memcpy(&dst, he->h_addr, sizeof(dst));
+			}
+			break;
+
+		case 'c':
+			count = strtol(optarg, &endp, 10);
+			if (count <= 0 || *endp != '\0')
+				usage();
+			break;
+
+		case 'f':
+			flood = 1;
+			break;
+
+		case 'i':
+			wait = strtol(optarg, &endp, 10);
+			if (wait <= 0 || *endp != '\0')
+				usage();
+			break;
+
+		case 'n':
+			numeric = 1;
+			break;
+
+		case 'S':
+			if (!bt_aton(optarg, &src)) {
+				if ((he = bt_gethostbyname(optarg)) == NULL)
+					errx(1, "%s: %s", optarg, hstrerror(h_errno));
+
+				memcpy(&src, he->h_addr, sizeof(src));
+			}
+			break;
+
+		case 's':
+                        echo_size = strtol(optarg, &endp, 10);
+                        if (echo_size < sizeof(int32_t) ||
+			    echo_size > NG_L2CAP_MAX_ECHO_SIZE ||
+			    *endp != '\0')
+				usage();
+			break;
+
+		case 'h':
+		default:
+			usage();
+			break;
+		}
+	}
+
+	if (memcmp(&dst, NG_HCI_BDADDR_ANY, sizeof(dst)) == 0)
+		usage();
+
+	he = bt_gethostbyaddr((const char *)&dst, sizeof(dst), AF_BLUETOOTH);
+	if (he == NULL || he->h_name == NULL || he->h_name[0] == '\0' || numeric)
+		asprintf(&rname, "%s", bt_ntoa(&dst, NULL));
+	else
+		rname = strdup(he->h_name);
+
+	if (rname == NULL)
+		errx(1, "Failed to create remote hostname");
+
+	s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_L2CAP);
+	if (s < 0)
+		err(2, "Could not create socket");
+
+	memset(&sa, 0, sizeof(sa));
+	sa.l2cap_len = sizeof(sa);
+	sa.l2cap_family = AF_BLUETOOTH;
+	memcpy(&sa.l2cap_bdaddr, &src, sizeof(sa.l2cap_bdaddr));
+
+	if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+		err(3,
+"Could not bind socket, src bdaddr=%s", bt_ntoa(&sa.l2cap_bdaddr, NULL));
+
+	memset(&sa, 0, sizeof(sa));
+	sa.l2cap_len = sizeof(sa);
+	sa.l2cap_family = AF_BLUETOOTH;
+	memcpy(&sa.l2cap_bdaddr, &dst, sizeof(sa.l2cap_bdaddr));
+
+	if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+		err(4,
+"Could not connect socket, dst bdaddr=%s", bt_ntoa(&sa.l2cap_bdaddr, NULL));
+
+	/* Fill pattern */
+	for (n = 0; n < echo_size; ) {
+		int32_t	avail = min(echo_size - n, PATTERN_SIZE);
+
+		memcpy(echo_data + n, pattern, avail);
+		n += avail;
+	}
+
+	/* Start ping'ing */
+	for (n = 0; count == -1 || count > 0; n ++) {
+		struct ng_btsocket_l2cap_raw_ping	r;
+		struct timeval				a, b;
+		int32_t					fail;
+
+		if (gettimeofday(&a, NULL) < 0)
+			err(5, "Could not gettimeofday(a)");
+
+		fail = 0;
+		*((int32_t *) echo_data) = htonl(n);
+
+		r.result = 0;
+		r.echo_size = echo_size;
+		r.echo_data = echo_data;
+		if (ioctl(s, SIOC_L2CAP_L2CA_PING, &r, sizeof(r)) < 0) {
+			r.result = errno;
+			fail = 1;
+/*
+			warn("Could not ping, dst bdaddr=%s",
+				bt_ntoa(&r.echo_dst, NULL));
+*/
+		}
+
+		if (gettimeofday(&b, NULL) < 0)
+			err(7, "Could not gettimeofday(b)");
+
+		tv_sub(&b, &a);
+
+		fprintf(stdout,
+"%d bytes from %s seq_no=%d time=%.3f ms result=%#x %s\n",
+			r.echo_size,
+			rname,
+			ntohl(*((int32_t *)(r.echo_data))),
+			tv2msec(&b), r.result,
+			((fail == 0)? "" : strerror(errno)));
+
+		if (!flood) {
+			/* Wait */
+			a.tv_sec = wait;
+			a.tv_usec = 0;
+			select(0, NULL, NULL, NULL, &a);
+		}
+
+		if (count != -1)
+			count --;
+	}
+
+	free(rname);
+	free(echo_data);
+	close(s);
+
+	return (0);
+} /* main */
+
+/* 
+ * a -= b, for timevals 
+ */
+
+static void
+tv_sub(struct timeval *a, struct timeval const *b)
+{
+	if (a->tv_usec < b->tv_usec) {
+		a->tv_usec += 1000000;
+		a->tv_sec -= 1;
+	}
+
+	a->tv_usec -= b->tv_usec;
+	a->tv_sec -= b->tv_sec;
+} /* tv_sub */
+
+/* 
+ * convert tv to msec 
+ */
+
+static double
+tv2msec(struct timeval const *tvp)
+{
+	return(((double)tvp->tv_usec)/1000.0 + ((double)tvp->tv_sec)*1000.0);
+} /* tv2msec */
+
+/* 
+ * Usage 
+ */
+
+static void
+usage(void)
+{
+	fprintf(stderr, "Usage: l2ping [-fhn] -a remote " \
+		"[-c count] [-i wait] [-S source] [-s size]\n");
+	fprintf(stderr, "Where:\n");
+	fprintf(stderr, "  -a remote  Specify remote device to ping\n");
+	fprintf(stderr, "  -c count   Number of packets to send\n");
+	fprintf(stderr, "  -f         No delay between packets\n");
+	fprintf(stderr, "  -h         Display this message\n");
+	fprintf(stderr, "  -i wait    Delay between packets (sec)\n");
+	fprintf(stderr, "  -n         Numeric output only\n");
+	fprintf(stderr, "  -S source  Specify source device\n");
+	fprintf(stderr, "  -s size    Packet size (bytes), " \
+		"between %zd and %zd\n", sizeof(int32_t), NG_L2CAP_MAX_ECHO_SIZE);
+	
+	exit(255);
+} /* usage */
+
diff --git a/usr.sbin/rfcomm_pppd/Makefile b/usr.sbin/rfcomm_pppd/Makefile
new file mode 100644
index 0000000000..6478d05c65
--- /dev/null
+++ b/usr.sbin/rfcomm_pppd/Makefile
@@ -0,0 +1,14 @@
+# $Id: Makefile,v 1.7 2003/09/07 18:32:11 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/rfcomm_pppd/Makefile 121054 2003-10-12 22:04:24Z emax $
+
+.PATH:	${.CURDIR}/../../usr.bin/rfcomm_sppd
+
+PROG=		rfcomm_pppd
+MAN=		rfcomm_pppd.8
+SRCS=		rfcomm_pppd.c rfcomm_sdp.c
+WARNS?=		2
+
+DPADD=		${LIBBLUETOOTH} ${LIBSDP}
+LDADD=		-lbluetooth -lsdp
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rfcomm_pppd/rfcomm_pppd.8 b/usr.sbin/rfcomm_pppd/rfcomm_pppd.8
new file mode 100644
index 0000000000..587ada8ac7
--- /dev/null
+++ b/usr.sbin/rfcomm_pppd/rfcomm_pppd.8
@@ -0,0 +1,354 @@
+.\" Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: rfcomm_pppd.8,v 1.7 2003/09/07 18:32:11 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd February 4, 2003
+.Dt RFCOMM_PPPD 8
+.Os
+.Sh NAME
+.Nm rfcomm_pppd
+.Nd RFCOMM PPP daemon
+.Sh SYNOPSIS
+.Nm
+.Fl c
+.Op Fl dh
+.Fl a Ar address
+.Fl C Ar channel
+.Fl l Ar label
+.Fl u Ar N
+.Nm
+.Fl s
+.Op Fl dDhS
+.Op Fl a Ar address
+.Fl C Ar channel
+.Fl l Ar label
+.Sh DESCRIPTION
+The
+.Nm
+daemon is a simple wrapper daemon that allows the use of
+.Xr ppp 8
+via an RFCOMM connection.
+It can operate in two modes: client and server.
+.Pp
+In client mode,
+.Nm
+opens an RFCOMM connection to the specified server's
+.Ar BD_ADRR
+and
+.Ar channel .
+Once the RFCOMM connection is established,
+.Nm
+executes
+.Xr ppp 8
+in
+.Fl direct
+mode with the specified
+.Ar label .
+Likewise,
+.Xr ppp 8
+operates over the RFCOMM connection just like it would over a standard serial
+port, thus allowing a user to
+.Dq "dial out"
+and connect to the Internet.
+.Pp
+In server mode,
+.Nm
+opens an RFCOMM socket and listens for incoming connections from remote clients.
+Once the new incoming connection is accepted,
+.Nm
+forks and executes
+.Xr ppp 8
+in
+.Fl direct
+mode with the specified
+.Ar label .
+Likewise,
+.Xr ppp 8
+operates over the RFCOMM connection just like it would over a standard serial
+port, thus providing network connectivity to remote clients.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar address
+In client mode, this required option specifies the address of the remote
+RFCOMM server.
+In server mode, this option can be used to specify the local
+address to listen on.
+By default, in server mode, the daemon will listen on
+.Dv ANY
+address.
+The address can be specified as BD_ADDR or name.
+If a name was specified, the
+.Nm
+utility will attempt to resolve the name via
+.Xr bt_gethostbyname 3 .
+.It Fl C Ar channel
+In both client and server mode, this required option specifies the RFCOMM
+channel to connect to or listen on.
+In server mode, the channel should be a number between 1 and 30.
+In client mode, the channel could either be a number between 1 and 30
+or a service name.
+Supported service names are:
+.Cm DUN
+(Dial-Up Networking) and
+.Cm LAN
+(LAN Access Using PPP).
+If a service name is used instead of a numeric channel number, then
+.Nm
+will try to obtain an RFCOMM channel number via SDP
+(Service Discovery Protocol).
+.It Fl c
+Act as an RFCOMM client.
+This is the default mode.
+.It Fl d
+Do not detach from the controlling terminal, i.e., run in foreground.
+.It Fl D
+In server mode, register the
+.Cm DUN
+(Dial-Up Networking) service in addition to the
+.Cm LAN
+(LAN Access Using PPP) service.
+AT-command exchange can be faked with
+.Xr ppp 8
+chat script.
+.It Fl h
+Display usage message and exit.
+.It Fl l Ar label
+In both client and server mode, this required option specifies which
+.Xr ppp 8
+label will be used.
+.It Fl S
+In server mode, register the
+.Cm SP
+(Serial Port) service in addition to the
+.Cm LAN
+(LAN Access Using PPP) service.
+.Pp
+It appears that some cell phones are using the so-called
+.Dq "callback mechanism" .
+In this scenario, the user is trying to connect his cell phone to the Internet,
+while the user's host computer is acting as the gateway server.
+It seems that it is not possible to tell the phone to just connect and start
+using the
+.Cm LAN
+service.
+Instead, the user's host computer must
+.Dq "jump start"
+the phone by connecting to the phone's
+.Cm SP
+service.
+What happens next is the phone kills the existing connection and opens another
+connection back to the user's host computer.
+The phone really wants to use the
+.Cm LAN
+service, but for whatever reason it looks for the
+.Cm SP
+service on the user's host computer.
+This brain-damaged behavior was reported for the Nokia 6600 and the
+Sony/Ericsson P900.
+.It Fl s
+Act as an RFCOMM server.
+.It Fl u Ar N
+This option maps directly to the
+.Fl unit
+.Xr ppp 8
+command-line option and tells
+.Nm
+to instruct
+.Xr ppp 8
+to only attempt to open
+.Pa /dev/tun Ns Ar N .
+This option only works in client mode.
+.El
+.Sh PPP CONFIGURATION
+.Ss Important Notes on PPP Configuration
+Special attention is required when adding new RFCOMM configurations to the
+existing PPP configuration.
+Please keep in mind that PPP will
+.Em always
+execute commands in the
+.Dq Li default
+label of your
+.Pa /etc/ppp/ppp.conf
+file.
+Please make sure that the
+.Dq Li default
+label
+.Em only
+contains commands that apply to
+.Em every
+other label.
+If you need to use PPP for both dialing out and accepting incoming
+RFCOMM connections, please make sure you have moved all commands related to
+dialing out from the
+.Dq Li default
+section into an appropriate outgoing label.
+.Ss RFCOMM Server
+One of the typical examples is the LAN access.
+In this example, an RFCOMM connection
+is used as a null-modem connection between a client and a server.
+Both client and server will start talking PPP right after the RFCOMM
+connection has been established.
+.Bd -literal -offset indent
+rfcomm-server:
+ set timeout 0
+ set lqrperiod 10
+ set ifaddr 10.0.0.1 10.0.0.2 255.255.255.0
+ enable lqr
+ accept lqr
+ accept dns
+ # Do not use PPP authentication. Assume that
+ # Bluetooth connection was authenticated already
+ disable pap
+ deny pap
+ disable chap
+ deny chap
+.Ed
+.Ss RFCOMM Client
+The
+.Nm
+utility supports both
+.Cm LAN
+(LAN Access Using PPP) and
+.Cm DUN
+(Dial-Up Networking) access.
+The client's configuration for
+.Cm LAN
+access is very similar to the server's and might look like this:
+.Bd -literal -offset indent
+rfcomm-client:
+ enable lqr
+ accept lqr
+ set dial
+ set timeout 0
+ disable iface-alias
+ set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0
+ # Do not use PPP authentication. Assume that
+ # Bluetooth connection was authenticated already
+ deny pap
+ disable pap
+ deny chap
+ disable chap
+.Ed
+.Pp
+The client's configuration for
+.Cm DUN
+access is different.
+In this scenario, the client gets connected to the virtual serial port on the
+server.
+To open a PPP session, the client must dial a number.
+Note that by default
+.Xr ppp 8
+will not execute any configured chat scripts.
+The
+.Ic force-scripts
+option can be used to override this behavior.
+An example configuration is shown below:
+.Bd -literal -offset indent
+rfcomm-dialup:
+ # This is IMPORTANT option
+ enable force-scripts
+
+ # You might want to change these
+ set authname
+ set authkey
+ set phone "*99***1#"
+
+ # You might want to adjust dial string as well
+ set dial "ABORT BUSY ABORT NO\\\\sCARRIER TIMEOUT 5 \\
+           \\"\\" AT OK-AT-OK ATE1Q0 OK \\\\dATDT\\\\T TIMEOUT 40 CONNECT"
+ set login
+ set timeout 30
+ enable dns
+ resolv rewrite
+
+ set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0
+ add default HISADDR
+.Ed
+.Pp
+Note that by adjusting the initialization string, one can make a CSD (Circuit
+Switched Data), HSCSD (High Speed Circuit Switched Data) or GPRS (General
+Packet Radio Service) connection.
+The availability of the particular connection
+type depends on the phone model and service plan activated on the phone.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+.Dl "rfcomm_pppd -s -a 00:01:02:03:04:05 -C 1 -l rfcomm-server"
+.Pp
+This command will start
+.Nm
+in the server mode.
+The RFCOMM server will listen on local address
+.Li 00:01:02:03:04:05
+and channel
+.Li 1 .
+Once the incoming connection has been accepted,
+.Nm
+will execute
+.Xr ppp 8
+in
+.Fl direct
+mode with the
+.Dq Li rfcomm-server
+label.
+.Pp
+.Dl "rfcomm_pppd -c -a 00:01:02:03:04:05 -C 1 -l rfcomm-client"
+.Pp
+This command will start
+.Nm
+in the client mode.
+.Nm
+will try to connect to the RFCOMM server at
+.Li 00:01:02:03:04:05
+address and channel
+.Li 1 .
+Once connected,
+.Nm
+will execute
+.Xr ppp 8
+in
+.Fl direct
+mode with the
+.Dq Li rfcomm-client
+label.
+.Sh SEE ALSO
+.Xr rfcomm_sppd 1 ,
+.Xr bluetooth 3 ,
+.Xr ng_btsocket 4 ,
+.Xr ppp 8 ,
+.Xr sdpcontrol 8 ,
+.Xr sdpd 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh CAVEATS
+The
+.Nm
+utility in server mode will try to register the Bluetooth LAN Access Over PPP
+service with the local SPD daemon.
+If the local SDP daemon is not running,
+.Nm
+will exit with an error.
diff --git a/usr.sbin/rfcomm_pppd/rfcomm_pppd.c b/usr.sbin/rfcomm_pppd/rfcomm_pppd.c
new file mode 100644
index 0000000000..fc8756a56f
--- /dev/null
+++ b/usr.sbin/rfcomm_pppd/rfcomm_pppd.c
@@ -0,0 +1,471 @@
+/*
+ * rfcomm_pppd.c
+ */
+
+/*-
+ * Copyright (c) 2001-2008 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: rfcomm_pppd.c,v 1.5 2003/09/07 18:32:11 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c 188130 2009-02-04 22:04:06Z emax $
+ */
+
+#include <bluetooth.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sdp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define RFCOMM_PPPD	"rfcomm_pppd"
+
+int		rfcomm_channel_lookup	(bdaddr_t const *local,
+					 bdaddr_t const *remote,
+					 int service, int *channel, int *error);
+
+static void	exec_ppp	(int s, char *unit, char *label);
+static void	sighandler	(int s);
+static void	usage		(void);
+
+static int	done;
+
+/* Main */
+int
+main(int argc, char *argv[])
+{
+	struct sockaddr_rfcomm   sock_addr;
+	char			*label = NULL, *unit = NULL, *ep = NULL;
+	bdaddr_t		 addr;
+	int			 s, channel, detach, server, service,
+				 regdun, regsp;
+	pid_t			 pid;
+
+	memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));
+	channel = 0;
+	detach = 1;
+	server = 0;
+	service = 0;
+	regdun = 0;
+	regsp = 0;
+
+	/* Parse command line arguments */
+	while ((s = getopt(argc, argv, "a:cC:dDhl:sSu:")) != -1) {
+		switch (s) {
+		case 'a': /* BDADDR */
+			if (!bt_aton(optarg, &addr)) {
+				struct hostent	*he = NULL;
+
+				if ((he = bt_gethostbyname(optarg)) == NULL)
+					errx(1, "%s: %s", optarg, hstrerror(h_errno));
+
+				memcpy(&addr, he->h_addr, sizeof(addr));
+			}
+			break;
+
+		case 'c': /* client */
+			server = 0;
+			break;
+
+		case 'C': /* RFCOMM channel */
+			channel = strtoul(optarg, &ep, 10);
+			if (*ep != '\0') {
+				channel = 0;
+				switch (tolower(optarg[0])) {
+				case 'd': /* DialUp Networking */
+					service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
+					break;
+
+				case 'l': /* LAN Access Using PPP */
+					service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
+					break;
+				}
+			}
+			break;
+
+		case 'd': /* do not detach */
+			detach = 0;
+			break;
+
+		case 'D': /* Register DUN service as well as LAN service */
+			regdun = 1;
+			break;
+
+		case 'l': /* PPP label */
+			label = optarg;
+			break;
+
+		case 's': /* server */
+			server = 1;
+			break;
+
+		case 'S': /* Register SP service as well as LAN service */
+			regsp = 1;
+			break;
+
+		case 'u': /* PPP -unit option */
+			strtoul(optarg, &ep, 10);
+			if (*ep != '\0')
+				usage();
+				/* NOT REACHED */
+
+			unit = optarg;
+			break;
+
+		case 'h':
+		default:
+			usage();
+			/* NOT REACHED */
+		}
+	}
+
+	/* Check if we got everything we wanted */
+	if (label == NULL)
+                errx(1, "Must specify PPP label");
+
+	if (!server) {
+		if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)
+                	errx(1, "Must specify server BD_ADDR");
+
+		/* Check channel, if was not set then obtain it via SDP */
+		if (channel == 0 && service != 0)
+			if (rfcomm_channel_lookup(NULL, &addr, service,
+							&channel, &s) != 0)
+				errc(1, s, "Could not obtain RFCOMM channel");
+	}
+
+        if (channel <= 0 || channel > 30)
+                errx(1, "Invalid RFCOMM channel number %d", channel);
+
+	openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER);
+
+	if (detach && daemon(0, 0) < 0) {
+		syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
+	if (s < 0) {
+		syslog(LOG_ERR, "Could not create socket. %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	if (server) {
+		struct sigaction	 sa;
+		void			*ss = NULL;
+		sdp_lan_profile_t	 lan;
+
+		/* Install signal handler */
+		memset(&sa, 0, sizeof(sa));
+		sa.sa_handler = sighandler;
+
+		if (sigaction(SIGTERM, &sa, NULL) < 0) {
+			syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)",
+				strerror(errno), errno);
+			exit(1);
+		}
+
+		if (sigaction(SIGHUP, &sa, NULL) < 0) {
+			syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)",
+				strerror(errno), errno);
+			exit(1);
+		}
+
+		if (sigaction(SIGINT, &sa, NULL) < 0) {
+			syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)",
+				strerror(errno), errno);
+			exit(1);
+		}
+
+		sa.sa_handler = SIG_IGN;
+		sa.sa_flags = SA_NOCLDWAIT;
+
+		if (sigaction(SIGCHLD, &sa, NULL) < 0) {
+			syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)",
+				strerror(errno), errno);
+			exit(1);
+		}
+
+		/* bind socket and listen for incoming connections */
+		sock_addr.rfcomm_len = sizeof(sock_addr);
+		sock_addr.rfcomm_family = AF_BLUETOOTH;
+		memcpy(&sock_addr.rfcomm_bdaddr, &addr,
+			sizeof(sock_addr.rfcomm_bdaddr));
+		sock_addr.rfcomm_channel = channel;
+
+		if (bind(s, (struct sockaddr *) &sock_addr,
+				sizeof(sock_addr)) < 0) {
+			syslog(LOG_ERR, "Could not bind socket. %s (%d)",
+				strerror(errno), errno);
+			exit(1);
+		}
+
+		if (listen(s, 10) < 0) {
+			syslog(LOG_ERR, "Could not listen on socket. %s (%d)",
+				strerror(errno), errno);
+			exit(1);
+		}
+
+		ss = sdp_open_local(NULL);
+		if (ss == NULL) {
+			syslog(LOG_ERR, "Unable to create local SDP session");
+			exit(1);
+		}
+
+		if (sdp_error(ss) != 0) {
+			syslog(LOG_ERR, "Unable to open local SDP session. " \
+				"%s (%d)", strerror(sdp_error(ss)),
+				sdp_error(ss));
+			exit(1);
+		}
+
+		memset(&lan, 0, sizeof(lan));
+		lan.server_channel = channel;
+
+		if (sdp_register_service(ss,
+				SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
+				&addr, (void *) &lan, sizeof(lan), NULL) != 0) {
+			syslog(LOG_ERR, "Unable to register LAN service with " \
+				"local SDP daemon. %s (%d)",
+				strerror(sdp_error(ss)), sdp_error(ss));
+			exit(1);
+		}
+
+		/*
+		 * Register DUN (Dial-Up Networking) service on the same
+		 * RFCOMM channel if requested. There is really no good reason
+		 * to not to support this. AT-command exchange can be faked
+		 * with chat script in ppp.conf
+		 */
+
+		if (regdun) {
+			sdp_dun_profile_t	dun;
+
+			memset(&dun, 0, sizeof(dun));
+			dun.server_channel = channel;
+
+			if (sdp_register_service(ss,
+					SDP_SERVICE_CLASS_DIALUP_NETWORKING,
+					&addr, (void *) &dun, sizeof(dun),
+					NULL) != 0) {
+				syslog(LOG_ERR, "Unable to register DUN " \
+					"service with local SDP daemon. " \
+					"%s (%d)", strerror(sdp_error(ss)),
+					sdp_error(ss));
+				exit(1);
+			}
+		}
+
+		/*
+		 * Register SP (Serial Port) service on the same RFCOMM channel
+		 * if requested. It appears that some cell phones are using so
+		 * called "callback mechanism". In this scenario user is trying
+		 * to connect his cell phone to the Internet, and, user's host
+		 * computer is acting as the gateway server. It seems that it
+		 * is not possible to tell the phone to just connect and start
+		 * using the LAN service. Instead the user's host computer must
+		 * "jump start" the phone by connecting to the phone's SP
+		 * service. What happens next is the phone kills the existing
+		 * connection and opens another connection back to the user's
+		 * host computer. The phone really wants to use LAN service,
+		 * but for whatever reason it looks for SP service on the
+		 * user's host computer. This brain damaged behavior was
+		 * reported for Nokia 6600 and Sony/Ericsson P900. Both phones
+		 * are Symbian-based phones. Perhaps this is a Symbian problem?
+		 */
+
+		if (regsp) {
+			sdp_sp_profile_t	sp;
+
+			memset(&sp, 0, sizeof(sp));
+			sp.server_channel = channel;
+
+			if (sdp_register_service(ss,
+					SDP_SERVICE_CLASS_SERIAL_PORT,
+					&addr, (void *) &sp, sizeof(sp),
+					NULL) != 0) {
+				syslog(LOG_ERR, "Unable to register SP " \
+					"service with local SDP daemon. " \
+					"%s (%d)", strerror(sdp_error(ss)),
+					sdp_error(ss));
+				exit(1);
+			}
+		}
+		
+		for (done = 0; !done; ) {
+			socklen_t	len = sizeof(sock_addr);
+			int		s1 = accept(s, (struct sockaddr *) &sock_addr, &len);
+
+			if (s1 < 0) {
+				syslog(LOG_ERR, "Could not accept connection " \
+					"on socket. %s (%d)", strerror(errno),
+					errno);
+				exit(1);
+			}
+				
+			pid = fork();
+			if (pid == (pid_t) -1) {
+				syslog(LOG_ERR, "Could not fork(). %s (%d)",
+					strerror(errno), errno);
+				exit(1);
+			}
+
+			if (pid == 0) {
+				sdp_close(ss);
+				close(s);
+
+				/* Reset signal handler */
+				memset(&sa, 0, sizeof(sa));
+				sa.sa_handler = SIG_DFL;
+
+				sigaction(SIGTERM, &sa, NULL);
+				sigaction(SIGHUP, &sa, NULL);
+				sigaction(SIGINT, &sa, NULL);
+				sigaction(SIGCHLD, &sa, NULL);
+
+				/* Become daemon */
+				daemon(0, 0);
+
+				/*
+				 * XXX Make sure user does not shoot himself
+				 * in the foot. Do not pass unit option to the
+				 * PPP when operating in the server mode.
+				 */
+
+				exec_ppp(s1, NULL, label);
+			} else
+				close(s1);
+		}
+	} else {
+		sock_addr.rfcomm_len = sizeof(sock_addr);
+		sock_addr.rfcomm_family = AF_BLUETOOTH;
+		memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY,
+			sizeof(sock_addr.rfcomm_bdaddr));
+		sock_addr.rfcomm_channel = 0;
+
+		if (bind(s, (struct sockaddr *) &sock_addr,
+				sizeof(sock_addr)) < 0) {
+			syslog(LOG_ERR, "Could not bind socket. %s (%d)",
+				strerror(errno), errno);
+			exit(1);
+		}
+
+		memcpy(&sock_addr.rfcomm_bdaddr, &addr,
+			sizeof(sock_addr.rfcomm_bdaddr));
+		sock_addr.rfcomm_channel = channel;
+
+		if (connect(s, (struct sockaddr *) &sock_addr,
+				sizeof(sock_addr)) < 0) {
+			syslog(LOG_ERR, "Could not connect socket. %s (%d)",
+				strerror(errno), errno);
+			exit(1);
+		}
+
+		exec_ppp(s, unit, label);
+	}
+
+	exit(0);
+} /* main */
+
+/* 
+ * Redirects stdin/stdout to s, stderr to /dev/null and exec
+ * 'ppp -direct -quiet [-unit N] label'. Never returns.
+ */
+
+static void
+exec_ppp(int s, char *unit, char *label)
+{
+	char	 ppp[] = "/usr/sbin/ppp";
+	char	*ppp_args[] = { ppp,  "-direct", "-quiet",
+				NULL, NULL,      NULL,     NULL };
+
+	close(0);
+	if (dup(s) < 0) {
+		syslog(LOG_ERR, "Could not dup(0). %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	close(1);
+	if (dup(s) < 0) {
+		syslog(LOG_ERR, "Could not dup(1). %s (%d)",
+			strerror(errno), errno);
+		exit(1);
+	}
+
+	close(2);
+	open("/dev/null", O_RDWR);
+
+	if (unit != NULL) {
+		ppp_args[3] = "-unit";
+		ppp_args[4] = unit;
+		ppp_args[5] = label;
+	} else
+		ppp_args[3] = label;
+
+	if (execv(ppp, ppp_args) < 0) {
+		syslog(LOG_ERR, "Could not exec(%s -direct -quiet%s%s %s). " \
+			"%s (%d)", ppp, (unit != NULL)? " -unit " : "",
+			(unit != NULL)? unit : "", label,
+			strerror(errno), errno);
+		exit(1);
+	}
+} /* run_ppp */
+
+/* Signal handler */
+static void
+sighandler(int s)
+{
+	done = 1;
+} /* sighandler */
+
+/* Display usage and exit */
+static void
+usage(void)
+{
+	fprintf(stdout,
+"Usage: %s options\n" \
+"Where options are:\n" \
+"\t-a address   Address to listen on or connect to (required for client)\n" \
+"\t-c           Act as a clinet (default)\n" \
+"\t-C channel   RFCOMM channel to listen on or connect to (required)\n" \
+"\t-d           Run in foreground\n" \
+"\t-D           Register Dial-Up Networking service (server mode only)\n" \
+"\t-l label     Use PPP label (required)\n" \
+"\t-s           Act as a server\n" \
+"\t-S           Register Serial Port service (server mode only)\n" \
+"\t-u N         Tell PPP to operate on /dev/tunN (client mode only)\n" \
+"\t-h           Display this message\n", RFCOMM_PPPD);
+
+	exit(255);
+} /* usage */
+
diff --git a/usr.sbin/sdpcontrol/Makefile b/usr.sbin/sdpcontrol/Makefile
new file mode 100644
index 0000000000..60a54ff90b
--- /dev/null
+++ b/usr.sbin/sdpcontrol/Makefile
@@ -0,0 +1,12 @@
+# $Id: Makefile,v 1.1 2003/09/08 02:27:27 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/sdpcontrol/Makefile 121054 2003-10-12 22:04:24Z emax $
+
+PROG=		sdpcontrol
+MAN=		sdpcontrol.8
+SRCS=		sdpcontrol.c search.c
+WARNS?=		2
+
+DPADD=		${LIBBLUETOOTH} ${LIBSDP}
+LDADD=		-lbluetooth -lsdp
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sdpcontrol/sdpcontrol.8 b/usr.sbin/sdpcontrol/sdpcontrol.8
new file mode 100644
index 0000000000..6c0f1ad5a1
--- /dev/null
+++ b/usr.sbin/sdpcontrol/sdpcontrol.8
@@ -0,0 +1,118 @@
+.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" 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.
+.\"
+.\" $Id: sdpcontrol.8,v 1.1 2003/09/08 02:27:27 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8 267668 2014-06-20 09:57:27Z bapt $
+.\"
+.Dd September 7, 2003
+.Dt SDPCONTROL 8
+.Os
+.Sh NAME
+.Nm sdpcontrol
+.Nd SDP query utility
+.Sh SYNOPSIS
+.Nm
+.Fl h
+.Nm
+.Fl a Ar address
+.Ar command
+.Op Ar parameters ...
+.Nm
+.Fl l
+.Op Fl c Ar path
+.Ar command
+.Op Ar parameters ...
+.Sh DESCRIPTION
+The
+.Nm
+utility attempts to query the specified Service Discovery Protocol (SDP) server.
+Remote SDP servers are identified by their address.
+Connection to the local SDP server is made via the control socket.
+The
+.Nm
+utility uses Service Search Attribute Requests and prints results to
+standard output and error messages to standard error.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar address
+Connect to the remote device with the specified address.
+The address can be specified as BD_ADDR or a name.
+If a name was specified, the
+.Nm
+utility attempts to resolve the name via
+.Xr bt_gethostbyname 3 .
+.It Fl c Ar path
+Specify path to the control socket.
+The default path is
+.Pa /var/run/sdp .
+.It Fl h
+Display usage message and exit.
+.It Fl l
+Query the local SDP server via the control socket.
+.It Ar command
+One of the supported commands (see below).
+The special command
+.Cm help
+can be used to obtain a list of all supported commands.
+To get more information about a specific command, use
+.Cm help Ar command .
+.It Ar parameters
+One or more optional space separated command parameters.
+.El
+.Sh COMMANDS
+The currently supported node commands in
+.Nm
+are:
+.Pp
+.Bl -tag -width "Browse" -offset indent -compact
+.It Cm Browse
+.It Cm Search
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr bluetooth 3 ,
+.Xr sdp 3
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh CAVEATS
+The
+.Nm
+utility only implements client side functionality.
+.Pp
+The
+.Nm
+utility only requests the following attributes from the SDP server:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+Service Record Handle
+.It
+Service Class ID List
+.It
+Protocol Descriptor List
+.It
+Bluetooth Profile Descriptor List
+.El
diff --git a/usr.sbin/sdpcontrol/sdpcontrol.c b/usr.sbin/sdpcontrol/sdpcontrol.c
new file mode 100644
index 0000000000..f240313e07
--- /dev/null
+++ b/usr.sbin/sdpcontrol/sdpcontrol.c
@@ -0,0 +1,219 @@
+/*
+ * sdpcontrol.c
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: sdpcontrol.c,v 1.1 2003/09/08 02:27:27 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c 133178 2004-08-05 16:32:41Z emax $
+ */
+
+#include <assert.h>
+#include <bluetooth.h>
+#include <err.h>
+#include <errno.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "sdpcontrol.h"
+
+/* Prototypes */
+static int                  do_sdp_command	(bdaddr_p, char const *, int,
+						 int, char **);
+static struct sdp_command * find_sdp_command	(char const *,
+						 struct sdp_command *); 
+static void                 print_sdp_command	(struct sdp_command *);
+static void                 usage		(void);
+
+/* Main */
+int
+main(int argc, char *argv[])
+{
+	char const	*control = SDP_LOCAL_PATH;
+	int		 n, local;
+	bdaddr_t	 bdaddr;
+
+	memset(&bdaddr, 0, sizeof(bdaddr));
+	local = 0;
+
+	/* Process command line arguments */
+	while ((n = getopt(argc, argv, "a:c:lh")) != -1) {
+		switch (n) {
+		case 'a': /* bdaddr */
+			if (!bt_aton(optarg, &bdaddr)) {
+				struct hostent  *he = NULL;
+
+				if ((he = bt_gethostbyname(optarg)) == NULL)
+					errx(1, "%s: %s", optarg, hstrerror(h_errno));
+ 
+				memcpy(&bdaddr, he->h_addr, sizeof(bdaddr));
+			}
+			break;
+
+		case 'c': /* control socket */
+			control = optarg;
+			break;
+
+		case 'l': /* local sdpd */
+			local = 1;
+			break;
+
+		case 'h':
+		default:
+			usage();
+			/* NOT REACHED */
+		}
+	}
+
+	argc -= optind; 
+	argv += optind;
+
+	if (*argv == NULL)
+		usage();
+
+	return (do_sdp_command(&bdaddr, control, local, argc, argv));
+}
+
+/* Execute commands */
+static int
+do_sdp_command(bdaddr_p bdaddr, char const *control, int local,
+		int argc, char **argv)
+{
+	char			*cmd = argv[0];
+	struct sdp_command	*c = NULL;
+	void			*xs = NULL;
+	int			 e, help;
+
+	help = 0;
+	if (strcasecmp(cmd, "help") == 0) {
+		argc --;
+		argv ++;
+
+		if (argc <= 0) {
+			fprintf(stdout, "Supported commands:\n");
+			print_sdp_command(sdp_commands);
+			fprintf(stdout, "\nFor more information use " \
+				"'help command'\n");
+
+			return (OK);
+		}
+
+		help = 1;
+		cmd = argv[0];
+	}
+
+	c = find_sdp_command(cmd, sdp_commands);
+	if (c == NULL) {
+		fprintf(stdout, "Unknown command: \"%s\"\n", cmd);
+		return (ERROR);
+	}
+
+	if (!help) {
+		if (!local) {
+			if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0)
+				usage();
+
+			xs = sdp_open(NG_HCI_BDADDR_ANY, bdaddr);
+		} else
+			xs = sdp_open_local(control);
+
+		if (xs == NULL)
+			errx(1, "Could not create SDP session object");
+		if (sdp_error(xs) == 0)
+			e = (c->handler)(xs, -- argc, ++ argv);
+		else
+			e = ERROR;
+	} else
+		e = USAGE;
+
+	switch (e) {
+	case OK:
+	case FAILED:
+		break;
+
+	case ERROR:
+		fprintf(stdout, "Could not execute command \"%s\". %s\n",
+			cmd, strerror(sdp_error(xs)));
+		break;
+
+	case USAGE:
+		fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);
+		break;
+
+	default: assert(0); break;
+	}
+
+	sdp_close(xs);
+
+	return (e);
+} /* do_sdp_command */
+
+/* Try to find command in specified category */
+static struct sdp_command *
+find_sdp_command(char const *command, struct sdp_command *category)   
+{
+	struct sdp_command	*c = NULL;
+
+	for (c = category; c->command != NULL; c++) {
+		char	*c_end = strchr(c->command, ' ');
+
+		if (c_end != NULL) {
+			int	len = c_end - c->command;
+
+			if (strncasecmp(command, c->command, len) == 0)
+				return (c);
+		} else if (strcasecmp(command, c->command) == 0)
+				return (c);
+	}
+
+	return (NULL);
+} /* find_sdp_command */
+
+/* Print commands in specified category */
+static void
+print_sdp_command(struct sdp_command *category)
+{
+	struct sdp_command	*c = NULL;
+
+	for (c = category; c->command != NULL; c++)
+		fprintf(stdout, "\t%s\n", c->command);
+} /* print_sdp_command */
+
+/* Usage */
+static void
+usage(void)
+{
+	fprintf(stderr,
+"Usage: sdpcontrol options command\n" \
+"Where options are:\n"
+"	-a address	address to connect to\n" \
+"	-c path		path to the control socket (default is %s)\n" \
+"	-h		display usage and quit\n" \
+"	-l		connect to the local SDP server via control socket\n" \
+"	command		one of the supported commands\n", SDP_LOCAL_PATH);
+	exit(255);
+} /* usage */
+
diff --git a/usr.sbin/sdpcontrol/sdpcontrol.h b/usr.sbin/sdpcontrol/sdpcontrol.h
new file mode 100644
index 0000000000..a4267fd698
--- /dev/null
+++ b/usr.sbin/sdpcontrol/sdpcontrol.h
@@ -0,0 +1,49 @@
+/*
+ * sdpcontrol.h
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: sdpcontrol.h,v 1.1 2003/09/08 02:27:27 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.h 121054 2003-10-12 22:04:24Z emax $
+ */
+
+#ifndef __SDPCONTROL_H__
+#define __SDPCONTROL_H__
+
+#define OK			0	/* everything was OK */
+#define ERROR			1	/* could not execute command */
+#define FAILED			2	/* error was reported */
+#define USAGE			3	/* invalid parameters */
+
+struct sdp_command {
+	char const		*command;
+	char const		*description;
+	int			(*handler)(void *, int, char **);
+};
+
+extern struct sdp_command	sdp_commands[];
+
+#endif /* __SDPCONTROL_H__ */
+
diff --git a/usr.bin/sdpquery/search.c b/usr.sbin/sdpcontrol/search.c
similarity index 77%
rename from usr.bin/sdpquery/search.c
rename to usr.sbin/sdpcontrol/search.c
index 7b75ade2da..3463586935 100644
--- a/usr.bin/sdpquery/search.c
+++ b/usr.sbin/sdpcontrol/search.c
@@ -1,34 +1,3 @@
-/* $NetBSD: search.c,v 1.6 2007/11/06 21:35:52 plunky Exp $ */
-/* $DragonFly: src/usr.bin/sdpquery/search.c,v 1.2 2008/02/11 20:09:42 swildner Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
 /*
  * search.c
  *
@@ -56,20 +25,17 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: search.c,v 1.6 2007/11/06 21:35:52 plunky Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpcontrol/search.c,v 1.4 2005/05/27 19:11:33 emax Exp $
+ * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpcontrol/search.c 173335 2007-11-04 21:24:33Z emax $
  */
 
 #include <netinet/in.h>
 #include <bluetooth.h>
-#include <err.h>
-#include <errno.h>
 #include <ctype.h>
 #include <sdp.h>
 #include <stdio.h>
 #include <stdlib.h>
-
-#include "sdpquery.h"
+#include "sdpcontrol.h"
 
 /* List of the attributes we are looking for */
 static uint32_t	attrs[] =
@@ -97,9 +63,9 @@ static sdp_attr_t	values[NRECS * attrs_len];
 /*
  * Print Service Class ID List
  *
- * The ServiceClassIDList attribute consists of a data element sequence in
+ * The ServiceClassIDList attribute consists of a data element sequence in 
  * which each data element is a UUID representing the service classes that
- * a given service record conforms to. The UUIDs are listed in order from
+ * a given service record conforms to. The UUIDs are listed in order from 
  * the most specific class to the most general class. The ServiceClassIDList
  * must contain at least one service class UUID.
  */
@@ -175,15 +141,15 @@ print_service_class_id_list(uint8_t const *start, uint8_t const *end)
 /*
  * Print Protocol Descriptor List
  *
- * If the ProtocolDescriptorList describes a single stack, it takes the form
- * of a data element sequence in which each element of the sequence is a
- * protocol descriptor. Each protocol descriptor is, in turn, a data element
- * sequence whose first element is a UUID identifying the protocol and whose
- * successive elements are protocol-specific parameters. The protocol
- * descriptors are listed in order from the lowest layer protocol to the
+ * If the ProtocolDescriptorList describes a single stack, it takes the form 
+ * of a data element sequence in which each element of the sequence is a 
+ * protocol descriptor. Each protocol descriptor is, in turn, a data element 
+ * sequence whose first element is a UUID identifying the protocol and whose 
+ * successive elements are protocol-specific parameters. The protocol 
+ * descriptors are listed in order from the lowest layer protocol to the 
  * highest layer protocol used to gain access to the service. If it is possible
- * for more than one kind of protocol stack to be used to gain access to the
- * service, the ProtocolDescriptorList takes the form of a data element
+ * for more than one kind of protocol stack to be used to gain access to the 
+ * service, the ProtocolDescriptorList takes the form of a data element 
  * alternative where each member is a data element sequence as described above.
  */
 
@@ -292,21 +258,21 @@ print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
 		case SDP_DATA_STR8:
 		case SDP_DATA_URL8:
 			SDP_GET8(len, start);
-			fprintf(stdout, "%*.*s\n", len, len,  start);
+			fprintf(stdout, "%*.*s\n", len, len, (char *) start);
 			start += len;
 			break;
 
 		case SDP_DATA_STR16:
 		case SDP_DATA_URL16:
 			SDP_GET16(len, start);
-			fprintf(stdout, "%*.*s\n", len, len,  start);
+			fprintf(stdout, "%*.*s\n", len, len, (char *) start);
 			start += len;
 			break;
 
 		case SDP_DATA_STR32:
 		case SDP_DATA_URL32:
 			SDP_GET32(len, start);
-			fprintf(stdout, "%*.*s\n", len, len,  start);
+			fprintf(stdout, "%*.*s\n", len, len, (char *) start);
 			start += len;
 			break;
 
@@ -405,15 +371,15 @@ print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
 /*
  * Print Bluetooth Profile Descriptor List
  *
- * The BluetoothProfileDescriptorList attribute consists of a data element
- * sequence in which each element is a profile descriptor that contains
- * information about a Bluetooth profile to which the service represented by
- * this service record conforms. Each profile descriptor is a data element
- * sequence whose first element is the UUID assigned to the profile and whose
+ * The BluetoothProfileDescriptorList attribute consists of a data element 
+ * sequence in which each element is a profile descriptor that contains 
+ * information about a Bluetooth profile to which the service represented by 
+ * this service record conforms. Each profile descriptor is a data element 
+ * sequence whose first element is the UUID assigned to the profile and whose 
  * second element is a 16-bit profile version number. Each version of a profile
  * is assigned a 16-bit unsigned integer profile version number, which consists
- * of two 8-bit fields. The higher-order 8 bits contain the major version
- * number field and the lower-order 8 bits contain the minor version number
+ * of two 8-bit fields. The higher-order 8 bits contain the major version 
+ * number field and the lower-order 8 bits contain the minor version number 
  * field.
  */
 
@@ -522,67 +488,102 @@ print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end
 	}
 } /* print_bluetooth_profile_descriptor_list */
 
-struct service {
-	const char	*name;
-	uint16_t	class;
-	const char	*description;
-} services[] = {
-	{ "CIP",	SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS,
-	  "Common ISDN Access"		},
-	{ "CTP",	SDP_SERVICE_CLASS_CORDLESS_TELEPHONY,
-	  "Cordless Telephony"		},
-	{ "DUN",	SDP_SERVICE_CLASS_DIALUP_NETWORKING,
-	  "Dial Up Networking"		},
-	{ "FAX",	SDP_SERVICE_CLASS_FAX,
-	  "Fax"				},
-	{ "FTRN",	SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
-	  "Obex File Transfer"		},
-	{ "GN",		SDP_SERVICE_CLASS_GN,
-	  "Group ad-hoc Network"	},
-	{ "HID",	SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE,
-	  "Human Interface Device"	},
-	{ "HF",		SDP_SERVICE_CLASS_HANDSFREE,
-	  "Handsfree"			},
-	{ "HSET",	SDP_SERVICE_CLASS_HEADSET,
-	  "Headset"			},
-	{ "LAN",	SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
-	  "Lan access using PPP"	},
-	{ "NAP",	SDP_SERVICE_CLASS_NAP,
-	  "Network Access Point"	},
-	{ "OPUSH",	SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
-	  "OBEX Object Push"		},
-	{ "PANU",	SDP_SERVICE_CLASS_PANU,
-	  "Personal Area Networking User"		},
-	{ "SP",		SDP_SERVICE_CLASS_SERIAL_PORT,
-	  "Serial Port"			},
-	{ NULL,		0,
-	  NULL				}
-};
-
 /* Perform SDP search command */
-int
-do_sdp_search(bdaddr_t *laddr, bdaddr_t *raddr, int argc, char const **argv)
+static int
+do_sdp_search(void *xs, int argc, char **argv)
 {
-	struct service	*s;
-	void		*xs;
-	char		*ep;
-	uint32_t	 n;
-	int32_t		 type, value;
+	char		*ep = NULL;
+	int32_t		 n, type, value;
 	uint16_t	 service;
 
-	if (argc != 1)
-		goto usage;
+	/* Parse command line arguments */
+	switch (argc) {
+	case 1:
+		n = strtoul(argv[0], &ep, 16);
+		if (*ep != 0) {
+			switch (tolower(argv[0][0])) {
+			case 'c': /* CIP/CTP */
+				switch (tolower(argv[0][1])) {
+				case 'i':
+					service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS;
+					break;
+
+				case 't':
+					service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY;
+					break;
+
+				default:
+					return (USAGE);
+					/* NOT REACHED */
+				}
+				break;
 
-	service = strtoul(*argv, &ep, 16);
-	if (*ep != 0) {
-		for (s = services ; ; s++) {
-			if (s->name == NULL)
-				goto usage;
+			case 'd': /* DialUp Networking */
+				service = SDP_SERVICE_CLASS_DIALUP_NETWORKING;
+				break;
 
-			if (strcasecmp(s->name, *argv) == 0)
+			case 'f': /* Fax/OBEX File Transfer */
+				switch (tolower(argv[0][1])) {
+				case 'a':
+					service = SDP_SERVICE_CLASS_FAX;
+					break;
+
+				case 't':
+					service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER;
+					break;
+
+				default:
+					return (USAGE);
+					/* NOT REACHED */
+				}
 				break;
-		}
-		service = s->class;
+
+			case 'g': /* GN */
+				service = SDP_SERVICE_CLASS_GN;
+				break;
+
+			case 'h': /* Headset/HID */
+				switch (tolower(argv[0][1])) {
+				case 'i':
+					service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
+					break;
+
+				case 's':
+					service = SDP_SERVICE_CLASS_HEADSET;
+					break;
+
+				default:
+					return (USAGE);
+					/* NOT REACHED */
+				}
+				break;
+
+			case 'l': /* LAN Access Using PPP */
+				service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP;
+				break;
+
+			case 'n': /* NAP */
+				service = SDP_SERVICE_CLASS_NAP;
+				break;
+
+			case 'o': /* OBEX Object Push */
+				service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH;
+				break;
+
+			case 's': /* Serial Port */
+				service = SDP_SERVICE_CLASS_SERIAL_PORT;
+				break;
+
+			default:
+				return (USAGE);
+				/* NOT REACHED */
+			}
+		} else
+			service = (uint16_t) n;
+		break;
+
+	default:
+		return (USAGE);
 	}
 
 	/* Initialize attribute values array */
@@ -593,20 +594,10 @@ do_sdp_search(bdaddr_t *laddr, bdaddr_t *raddr, int argc, char const **argv)
 		values[n].value = buffer[n];
 	}
 
-	if (bdaddr_any(raddr))
-		xs = sdp_open_local(control_socket);
-	else
-		xs = sdp_open(laddr, raddr);
-
-	if (xs == NULL || (errno = sdp_error(xs)) != 0)
-		err(EXIT_FAILURE, "sdp_open");
-
 	/* Do SDP Service Search Attribute Request */
 	n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
 	if (n != 0)
-		err(EXIT_FAILURE, "sdp_search");
-
-	sdp_close(xs);
+		return (ERROR);
 
 	/* Print attributes values */
 	for (n = 0; n < values_len; n ++) {
@@ -657,38 +648,66 @@ do_sdp_search(bdaddr_t *laddr, bdaddr_t *raddr, int argc, char const **argv)
 		}
 	}
 
-	return EXIT_SUCCESS;
-
-usage:
-	fprintf(stderr, "Known services:\n");
-	for (s = services ; s->name != NULL ; s++)
-		fprintf(stderr, "\t%s\t%s\n", s->name, s->description);
-
-	return EXIT_FAILURE;
+	return (OK);
 } /* do_sdp_search */
 
 /* Perform SDP browse command */
-int
-do_sdp_browse(bdaddr_t *laddr, bdaddr_t *raddr, int argc, char const **argv)
+static int
+do_sdp_browse(void *xs, int argc, char **argv)
 {
 #undef	_STR
 #undef	STR
 #define	_STR(x)	#x
 #define	STR(x)	_STR(x)
 
-	static char	const * av[] = {
+	static char const * const	av[] = {
 		STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
 		NULL
-	};
+	}; 
 
 	switch (argc) {
 	case 0:
 		argc = 1;
-		argv =  (char const **) av;
+		argv = (char **) av;
 		/* FALL THROUGH */
 	case 1:
-		return (do_sdp_search(laddr, raddr, argc, argv));
+		return (do_sdp_search(xs, argc, argv));
 	}
 
-	return EXIT_FAILURE;
+	return (USAGE);
 } /* do_sdp_browse */
+
+/* List of SDP commands */
+struct sdp_command	sdp_commands[] = {
+{
+"Browse [<Group>]",
+"Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \
+"to browse. If omitted <Group> is set to Public Browse Group.\n\n" \
+"\t<Group> - xxxx; 16-bit UUID of the group to browse\n",
+do_sdp_browse
+},
+{
+"Search <Service>",
+"Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \
+"service to search for. For some services it is possible to use service name\n"\
+"instead of service UUID\n\n" \
+"\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \
+"\tKnown service names\n" \
+"\t===================\n" \
+"\tCIP   - Common ISDN Access\n" \
+"\tCTP   - Cordless Telephony\n" \
+"\tDUN   - DialUp Networking\n" \
+"\tFAX   - Fax\n" \
+"\tFTRN  - OBEX File Transfer\n" \
+"\tGN    - GN\n" \
+"\tHID   - Human Interface Device\n" \
+"\tHSET  - Headset\n" \
+"\tLAN   - LAN Access Using PPP\n" \
+"\tNAP   - Network Access Point\n" \
+"\tOPUSH - OBEX Object Push\n" \
+"\tSP    - Serial Port\n",
+do_sdp_search
+},
+{ NULL, NULL, NULL }
+};
+
diff --git a/usr.sbin/sdpd/Makefile b/usr.sbin/sdpd/Makefile
index 862f011fd8..086929db64 100644
--- a/usr.sbin/sdpd/Makefile
+++ b/usr.sbin/sdpd/Makefile
@@ -1,12 +1,13 @@
-# $NetBSD: Makefile,v 1.3 2007/05/28 12:06:41 tls Exp $
+# $Id: Makefile,v 1.1 2004/01/20 21:27:55 max Exp $
+# $FreeBSD: head/usr.sbin/bluetooth/sdpd/Makefile 177059 2008-03-11 16:51:07Z emax $
 
 PROG=		sdpd
 MAN=		sdpd.8
-SRCS=		bgd.c dun.c ftrn.c hf.c hset.c irmc.c irmc_command.c lan.c \
-		log.c main.c opush.c profile.c provider.c sar.c scr.c \
+SRCS=		bgd.c dun.c ftrn.c gn.c irmc.c irmc_command.c lan.c log.c \
+		main.c nap.c opush.c panu.c profile.c provider.c sar.c scr.c \
 		sd.c server.c sp.c srr.c ssar.c ssr.c sur.c uuid.c
-WARNS?=		2
 
-CFLAGS+=	-I${.CURDIR}/../../sys
+CFLAGS+=	-I${.CURDIR}
+WARNS?=		2
 
 .include <bsd.prog.mk>
diff --git a/usr.sbin/sdpd/bgd.c b/usr.sbin/sdpd/bgd.c
index a9cc7f5915..6d96c4d895 100644
--- a/usr.sbin/sdpd/bgd.c
+++ b/usr.sbin/sdpd/bgd.c
@@ -1,5 +1,3 @@
-/* $NetBSD: bgd.c,v 1.2 2007/11/09 20:08:40 plunky Exp $ */
-
 /*
  * bgd.c
  *
@@ -27,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: bgd.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/bgd.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: bgd.c,v 1.4 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/bgd.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <bluetooth.h>
@@ -84,9 +82,9 @@ static attr_t	bgd_profile_attrs[] = {
 	  bgd_profile_create_service_class_id_list },
 	{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
 	  common_profile_create_language_base_attribute_id_list },
-	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET, 
 	  bgd_profile_create_service_name },
-	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET, 
 	  bgd_profile_create_service_name },
 	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET,
 	  common_profile_create_service_provider_name },
@@ -95,14 +93,10 @@ static attr_t	bgd_profile_attrs[] = {
 	{ 0, NULL } /* end entry */
 };
 
-static uint16_t	bgd_profile_uuids[] = {
-	SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR,
-};
-
 profile_t	bgd_profile_descriptor = {
-	bgd_profile_uuids,
-	sizeof(bgd_profile_uuids),
+	SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR,
 	0,
-	NULL,
+	(profile_data_valid_p) NULL,
 	(attr_t const * const) &bgd_profile_attrs
 };
+
diff --git a/usr.sbin/sdpd/dun.c b/usr.sbin/sdpd/dun.c
index 980b66c550..f2f2d7414b 100644
--- a/usr.sbin/sdpd/dun.c
+++ b/usr.sbin/sdpd/dun.c
@@ -1,6 +1,3 @@
-/* $NetBSD: dun.c,v 1.2 2007/11/09 20:08:40 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/dun.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * dun.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: dun.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/dun.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: dun.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/dun.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <sys/queue.h>
@@ -87,12 +84,12 @@ dun_profile_create_protocol_descriptor_list(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_dun_profile_p	dun = (sdp_dun_profile_p) provider->data;
 
 	return (rfcomm_profile_create_protocol_descriptor_list(
 			buf, eob,
-			(uint8_t const *) &dun->server_channel, 1));
+			(uint8_t const *) &dun->server_channel, 1)); 
 }
 
 static int32_t
@@ -100,7 +97,7 @@ dun_profile_create_audio_feedback_support(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_dun_profile_p	dun = (sdp_dun_profile_p) provider->data;
 
 	if (buf + 2 > eob)
@@ -121,7 +118,7 @@ static attr_t	dun_profile_attrs[] = {
 	  dun_profile_create_bluetooth_profile_descriptor_list },
 	{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
 	  common_profile_create_language_base_attribute_id_list },
-	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET, 
 	  dun_profile_create_service_name },
 	{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
 	  dun_profile_create_protocol_descriptor_list },
@@ -130,17 +127,10 @@ static attr_t	dun_profile_attrs[] = {
 	{ 0, NULL } /* end entry */
 };
 
-static uint16_t dun_profile_uuids[] = {
-	SDP_SERVICE_CLASS_DIALUP_NETWORKING,
-	SDP_SERVICE_CLASS_GENERIC_NETWORKING,
-	SDP_UUID_PROTOCOL_L2CAP,
-	SDP_UUID_PROTOCOL_RFCOMM,
-};
-
 profile_t	dun_profile_descriptor = {
-	dun_profile_uuids,
-	sizeof(dun_profile_uuids),
+	SDP_SERVICE_CLASS_DIALUP_NETWORKING,
 	sizeof(sdp_dun_profile_t),
 	common_profile_server_channel_valid,
 	(attr_t const * const) &dun_profile_attrs
 };
+
diff --git a/usr.sbin/sdpd/ftrn.c b/usr.sbin/sdpd/ftrn.c
index 828efdfb72..59f27e6d22 100644
--- a/usr.sbin/sdpd/ftrn.c
+++ b/usr.sbin/sdpd/ftrn.c
@@ -1,6 +1,3 @@
-/* $NetBSD: ftrn.c,v 1.2 2007/11/09 20:08:40 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/ftrn.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * ftrn.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: ftrn.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/ftrn.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: ftrn.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/ftrn.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <sys/queue.h>
@@ -87,12 +84,12 @@ ftrn_profile_create_protocol_descriptor_list(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_ftrn_profile_p	ftrn = (sdp_ftrn_profile_p) provider->data;
 
 	return (obex_profile_create_protocol_descriptor_list(
 			buf, eob,
-			(uint8_t const *) &ftrn->server_channel, 1));
+			(uint8_t const *) &ftrn->server_channel, 1)); 
 }
 
 static attr_t	ftrn_profile_attrs[] = {
@@ -111,17 +108,10 @@ static attr_t	ftrn_profile_attrs[] = {
 	{ 0, NULL } /* end entry */
 };
 
-static uint16_t ftrn_profile_uuids[] = {
-	SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
-	SDP_UUID_PROTOCOL_L2CAP,
-	SDP_UUID_PROTOCOL_RFCOMM,
-	SDP_UUID_PROTOCOL_OBEX,
-};
-
 profile_t	ftrn_profile_descriptor = {
-	ftrn_profile_uuids,
-	sizeof(ftrn_profile_uuids),
+	SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
 	sizeof(sdp_ftrn_profile_t),
 	common_profile_server_channel_valid,
 	(attr_t const * const) &ftrn_profile_attrs
 };
+
diff --git a/usr.sbin/sdpd/gn.c b/usr.sbin/sdpd/gn.c
new file mode 100644
index 0000000000..7e421c3446
--- /dev/null
+++ b/usr.sbin/sdpd/gn.c
@@ -0,0 +1,172 @@
+/*
+ * gn.c
+ */
+
+/*-
+ * Copyright (c) 2008 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: gn.c,v 1.1 2008/03/11 00:02:42 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/gn.c 177358 2008-03-18 18:21:39Z emax $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+gn_profile_create_service_class_id_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static uint16_t	service_classes[] = {
+		SDP_SERVICE_CLASS_GN
+	};
+
+	return (common_profile_create_service_class_id_list(
+			buf, eob,
+			(uint8_t const *) service_classes,
+			sizeof(service_classes)));
+}
+
+static int32_t
+gn_profile_create_bluetooth_profile_descriptor_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static uint16_t	profile_descriptor_list[] = {
+		SDP_SERVICE_CLASS_GN,
+		0x0100
+	};
+
+	return (common_profile_create_bluetooth_profile_descriptor_list(
+			buf, eob,
+			(uint8_t const *) profile_descriptor_list,
+			sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+gn_profile_create_service_name(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static char	service_name[] = "Group Ad-hoc Network";
+
+	return (common_profile_create_string8(
+			buf, eob,
+			(uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+gn_profile_create_service_description(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static char	service_descr[] =
+				"Personal Group Ad-hoc Network Service";
+
+	return (common_profile_create_string8(
+			buf, eob,
+			(uint8_t const *) service_descr,
+			strlen(service_descr)));
+}
+
+static int32_t
+gn_profile_create_protocol_descriptor_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data;
+	sdp_gn_profile_p	gn = (sdp_gn_profile_p) provider->data;
+	
+	return (bnep_profile_create_protocol_descriptor_list(
+			buf, eob, (uint8_t const *) &gn->psm,
+			sizeof(gn->psm))); 
+}
+
+static int32_t
+gn_profile_create_security_description(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data;
+	sdp_gn_profile_p	gn = (sdp_gn_profile_p) provider->data;
+
+	return (bnep_profile_create_security_description(buf, eob,
+			(uint8_t const *) &gn->security_description,
+			sizeof(gn->security_description)));
+}
+
+static int32_t
+gn_profile_create_service_availability(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data;
+	sdp_gn_profile_p	gn = (sdp_gn_profile_p) provider->data;
+
+	return (common_profile_create_service_availability(buf, eob,
+			&gn->load_factor, 1));
+}
+
+static int32_t
+gn_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+	sdp_gn_profile_p	gn = (sdp_gn_profile_p) data;
+
+	return ((gn->psm == 0)? 0 : 1);
+}
+
+static attr_t	gn_profile_attrs[] = {
+	{ SDP_ATTR_SERVICE_RECORD_HANDLE,
+	  common_profile_create_service_record_handle },
+	{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
+	  gn_profile_create_service_class_id_list },
+	{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+	  gn_profile_create_protocol_descriptor_list },
+	{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+	  common_profile_create_language_base_attribute_id_list },
+	{ SDP_ATTR_SERVICE_AVAILABILITY,
+	  gn_profile_create_service_availability },
+	{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+	  gn_profile_create_bluetooth_profile_descriptor_list },
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET, 
+	  gn_profile_create_service_name },
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET, 
+	  gn_profile_create_service_description },
+	{ SDP_ATTR_SECURITY_DESCRIPTION, 
+	  gn_profile_create_security_description },
+	{ 0, NULL } /* end entry */
+};
+
+profile_t	gn_profile_descriptor = {
+	SDP_SERVICE_CLASS_GN,
+	sizeof(sdp_gn_profile_t),
+	gn_profile_data_valid,
+	(attr_t const * const) &gn_profile_attrs
+};
+
diff --git a/usr.sbin/sdpd/hf.c b/usr.sbin/sdpd/hf.c
deleted file mode 100644
index 3d3ccbda2e..0000000000
--- a/usr.sbin/sdpd/hf.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/* $NetBSD: hf.c,v 1.2 2007/11/09 20:08:40 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/hf.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/queue.h>
-#include <bluetooth.h>
-#include <sdp.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <netbt/rfcomm.h>
-
-#include "profile.h"
-#include "provider.h"
-
-static int32_t
-hf_profile_create_service_class_id_list(
-		uint8_t *buf, uint8_t const * const eob,
-		uint8_t const *data, uint32_t datalen)
-{
-	static uint16_t	service_classes[] = {
-		SDP_SERVICE_CLASS_HANDSFREE,
-		SDP_SERVICE_CLASS_GENERIC_AUDIO,
-	};
-
-	return (common_profile_create_service_class_id_list(
-			buf, eob,
-			(uint8_t const *) service_classes,
-			sizeof(service_classes)));
-}
-
-static int32_t
-hf_profile_create_protocol_descriptor_list(
-		uint8_t *buf, uint8_t const * const eob,
-		uint8_t const *data, uint32_t datalen)
-{
-	provider_t const	*provider = (provider_t const *) data;
-	sdp_hf_profile_t	*hf = (sdp_hf_profile_t *) provider->data;
-
-	return (rfcomm_profile_create_protocol_descriptor_list(
-			buf, eob,
-			(uint8_t const *) &hf->server_channel, 1));
-}
-
-static int32_t
-hf_profile_create_bluetooth_profile_descriptor_list(
-		uint8_t *buf, uint8_t const * const eob,
-		uint8_t const *data, uint32_t datalen)
-{
-	static uint16_t	profile_descriptor_list[] = {
-		SDP_SERVICE_CLASS_HANDSFREE,
-		0x0105
-	};
-
-	return (common_profile_create_bluetooth_profile_descriptor_list(
-			buf, eob,
-			(uint8_t const *) profile_descriptor_list,
-			sizeof(profile_descriptor_list)));
-}
-
-static int32_t
-hf_profile_create_service_name(
-		uint8_t *buf, uint8_t const * const eob,
-		uint8_t const *data, uint32_t datalen)
-{
-	static char	service_name[] = "Hands-Free unit";
-
-	return (common_profile_create_string8(
-			buf, eob,
-			(uint8_t const *) service_name, strlen(service_name)));
-}
-
-static int32_t
-hf_profile_create_supported_features(
-		uint8_t *buf, uint8_t const * const eob,
-		uint8_t const *data, uint32_t datalen)
-{
-	provider_t const	*provider = (provider_t const *) data;
-	sdp_hf_profile_t	*hf = (sdp_hf_profile_t *) provider->data;
-
-	if (buf + 3 > eob)
-		return (-1);
-
-	SDP_PUT8(SDP_DATA_UINT16, buf);
-	SDP_PUT16(hf->supported_features, buf);
-
-	return (3);
-}
-
-static int32_t
-hf_profile_data_valid(uint8_t const *data, uint32_t datalen)
-{
-	sdp_hf_profile_t const *hf = (sdp_hf_profile_t const *) data;
-
-	if (hf->server_channel < RFCOMM_CHANNEL_MIN
-	    || hf->server_channel > RFCOMM_CHANNEL_MAX
-	    || (hf->supported_features & ~0x001f))
-		return 0;
-
-	return 1;
-}
-
-static attr_t	hf_profile_attrs[] = {
-	{ SDP_ATTR_SERVICE_RECORD_HANDLE,
-	  common_profile_create_service_record_handle },
-	{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
-	  hf_profile_create_service_class_id_list },
-	{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
-	  hf_profile_create_protocol_descriptor_list },
-	{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
-	  hf_profile_create_bluetooth_profile_descriptor_list },
-	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
-	  hf_profile_create_service_name },
-	{ SDP_ATTR_SUPPORTED_FEATURES,
-	  hf_profile_create_supported_features },
-	{ 0, NULL } /* end entry */
-};
-
-static uint16_t	hf_profile_uuids[] = {
-	SDP_SERVICE_CLASS_HANDSFREE,
-	SDP_SERVICE_CLASS_GENERIC_AUDIO,
-	SDP_UUID_PROTOCOL_L2CAP,
-	SDP_UUID_PROTOCOL_RFCOMM,
-};
-
-profile_t	hf_profile_descriptor = {
-	hf_profile_uuids,
-	sizeof(hf_profile_uuids),
-	sizeof(sdp_hf_profile_t),
-	hf_profile_data_valid,
-	(attr_t const * const) &hf_profile_attrs
-};
diff --git a/usr.sbin/sdpd/hset.c b/usr.sbin/sdpd/hset.c
deleted file mode 100644
index d33e42e737..0000000000
--- a/usr.sbin/sdpd/hset.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/* $NetBSD: hset.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/hset.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * All rights reserved.
- *
- * Written by Iain Hibbert for Itronix Inc.
- *
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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/queue.h>
-#include <bluetooth.h>
-#include <sdp.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <netbt/rfcomm.h>
-
-#include "profile.h"
-#include "provider.h"
-
-static int32_t
-hset_profile_create_service_class_id_list(
-		uint8_t *buf, uint8_t const * const eob,
-		uint8_t const *data, uint32_t datalen)
-{
-	static uint16_t	service_classes[] = {
-		SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY,
-		SDP_SERVICE_CLASS_GENERIC_AUDIO,
-	};
-
-	return (common_profile_create_service_class_id_list(
-			buf, eob,
-			(uint8_t const *) service_classes,
-			sizeof(service_classes)));
-}
-
-static int32_t
-hset_profile_create_protocol_descriptor_list(
-		uint8_t *buf, uint8_t const * const eob,
-		uint8_t const *data, uint32_t datalen)
-{
-	provider_t const	*provider = (provider_t const *) data;
-	sdp_hset_profile_t	*hset = (sdp_hset_profile_t *) provider->data;
-
-	return (rfcomm_profile_create_protocol_descriptor_list(
-			buf, eob,
-			(uint8_t const *) &hset->server_channel, 1));
-}
-
-static int32_t
-hset_profile_create_bluetooth_profile_descriptor_list(
-		uint8_t *buf, uint8_t const * const eob,
-		uint8_t const *data, uint32_t datalen)
-{
-	static uint16_t	profile_descriptor_list[] = {
-		SDP_SERVICE_CLASS_HEADSET,
-		0x0100
-	};
-
-	return (common_profile_create_bluetooth_profile_descriptor_list(
-			buf, eob,
-			(uint8_t const *) profile_descriptor_list,
-			sizeof(profile_descriptor_list)));
-}
-
-static int32_t
-hset_profile_create_service_name(
-		uint8_t *buf, uint8_t const * const eob,
-		uint8_t const *data, uint32_t datalen)
-{
-	static char	service_name[] = "Voice Gateway";
-
-	return (common_profile_create_string8(
-			buf, eob,
-			(uint8_t const *) service_name, strlen(service_name)));
-}
-
-static int32_t
-hset_profile_data_valid(uint8_t const *data, uint32_t datalen)
-{
-	sdp_hset_profile_t const *hset = (sdp_hset_profile_t const *) data;
-
-	if (hset->server_channel < RFCOMM_CHANNEL_MIN
-	    || hset->server_channel > RFCOMM_CHANNEL_MAX)
-		return 0;
-
-	return 1;
-}
-
-static attr_t	hset_profile_attrs[] = {
-	{ SDP_ATTR_SERVICE_RECORD_HANDLE,
-	  common_profile_create_service_record_handle },
-	{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
-	  hset_profile_create_service_class_id_list },
-	{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
-	  hset_profile_create_protocol_descriptor_list },
-	{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
-	  hset_profile_create_bluetooth_profile_descriptor_list },
-	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
-	  hset_profile_create_service_name },
-	{ 0, NULL } /* end entry */
-};
-
-static uint16_t hset_profile_uuids[] = {
-	SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY,
-	SDP_SERVICE_CLASS_GENERIC_AUDIO,
-	SDP_UUID_PROTOCOL_L2CAP,
-	SDP_UUID_PROTOCOL_RFCOMM,
-	SDP_SERVICE_CLASS_HEADSET,
-};
-
-profile_t	hset_profile_descriptor = {
-	hset_profile_uuids,
-	sizeof(hset_profile_uuids),
-	sizeof(sdp_hset_profile_t),
-	hset_profile_data_valid,
-	(attr_t const * const) &hset_profile_attrs
-};
diff --git a/usr.sbin/sdpd/irmc.c b/usr.sbin/sdpd/irmc.c
index 2b78887d49..3ade415ac8 100644
--- a/usr.sbin/sdpd/irmc.c
+++ b/usr.sbin/sdpd/irmc.c
@@ -1,6 +1,3 @@
-/* $NetBSD: irmc.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/irmc.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * irmc.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: irmc.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/irmc.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: irmc.c,v 1.6 2004/01/13 19:31:54 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/irmc.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <sys/queue.h>
@@ -87,12 +84,12 @@ irmc_profile_create_protocol_descriptor_list(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_irmc_profile_p	irmc = (sdp_irmc_profile_p) provider->data;
 
 	return (obex_profile_create_protocol_descriptor_list(
 			buf, eob,
-			(uint8_t const *) &irmc->server_channel, 1));
+			(uint8_t const *) &irmc->server_channel, 1)); 
 }
 
 static int32_t
@@ -100,7 +97,7 @@ irmc_profile_create_supported_formats_list(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_irmc_profile_p	irmc = (sdp_irmc_profile_p) provider->data;
 
 	return (obex_profile_create_supported_formats_list(
@@ -127,17 +124,10 @@ static attr_t	irmc_profile_attrs[] = {
 	{ 0, NULL } /* end entry */
 };
 
-static uint16_t irmc_profile_uuids[] = {
-	SDP_SERVICE_CLASS_IR_MC_SYNC,
-	SDP_UUID_PROTOCOL_L2CAP,
-	SDP_UUID_PROTOCOL_RFCOMM,
-	SDP_UUID_PROTOCOL_OBEX,
-};
-
 profile_t	irmc_profile_descriptor = {
-	irmc_profile_uuids,
-	sizeof(irmc_profile_uuids),
+	SDP_SERVICE_CLASS_IR_MC_SYNC,
 	sizeof(sdp_irmc_profile_t),
 	obex_profile_data_valid,
 	(attr_t const * const) &irmc_profile_attrs
 };
+
diff --git a/usr.sbin/sdpd/irmc_command.c b/usr.sbin/sdpd/irmc_command.c
index 801bb19af8..62ef669ade 100644
--- a/usr.sbin/sdpd/irmc_command.c
+++ b/usr.sbin/sdpd/irmc_command.c
@@ -1,6 +1,3 @@
-/* $NetBSD: irmc_command.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/irmc_command.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * irmc_command_command_command.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: irmc_command.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/irmc_command.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: irmc_command.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/irmc_command.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <sys/queue.h>
@@ -87,12 +84,12 @@ irmc_command_profile_create_protocol_descriptor_list(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const		*provider = (provider_t const *) data;
+	provider_p			provider = (provider_p) data;
 	sdp_irmc_command_profile_p	irmc_command = (sdp_irmc_command_profile_p) provider->data;
 
 	return (obex_profile_create_protocol_descriptor_list(
 			buf, eob,
-			(uint8_t const *) &irmc_command->server_channel, 1));
+			(uint8_t const *) &irmc_command->server_channel, 1)); 
 }
 
 static attr_t	irmc_command_profile_attrs[] = {
@@ -111,17 +108,10 @@ static attr_t	irmc_command_profile_attrs[] = {
 	{ 0, NULL } /* end entry */
 };
 
-static uint16_t	irmc_command_profile_uuids[] = {
-	SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND,
-	SDP_UUID_PROTOCOL_L2CAP,
-	SDP_UUID_PROTOCOL_RFCOMM,
-	SDP_UUID_PROTOCOL_OBEX,
-};
-
 profile_t	irmc_command_profile_descriptor = {
-	irmc_command_profile_uuids,
-	sizeof(irmc_command_profile_uuids),
+	SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND,
 	sizeof(sdp_irmc_command_profile_t),
 	common_profile_server_channel_valid,
 	(attr_t const * const) &irmc_command_profile_attrs
 };
+
diff --git a/usr.sbin/sdpd/lan.c b/usr.sbin/sdpd/lan.c
index 1cd054f3ff..82b1457dd0 100644
--- a/usr.sbin/sdpd/lan.c
+++ b/usr.sbin/sdpd/lan.c
@@ -1,6 +1,3 @@
-/* $NetBSD: lan.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/lan.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * lan.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: lan.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/lan.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: lan.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/lan.c 177358 2008-03-18 18:21:39Z emax $
  */
 
 #include <arpa/inet.h>
@@ -89,12 +86,12 @@ lan_profile_create_protocol_descriptor_list(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_lan_profile_p	lan = (sdp_lan_profile_p) provider->data;
 
 	return (rfcomm_profile_create_protocol_descriptor_list(
 			buf, eob,
-			(uint8_t const *) &lan->server_channel, 1));
+			(uint8_t const *) &lan->server_channel, 1)); 
 }
 
 static int32_t
@@ -102,16 +99,11 @@ lan_profile_create_service_availability(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_lan_profile_p	lan = (sdp_lan_profile_p) provider->data;
 
-	if (buf + 2 > eob)
-		return (-1);
-
-	SDP_PUT8(SDP_DATA_UINT8, buf);
-	SDP_PUT8(lan->load_factor, buf);
-
-	return (2);
+	return (common_profile_create_service_availability(buf, eob,
+			&lan->load_factor, 1));
 }
 
 static int32_t
@@ -119,7 +111,7 @@ lan_profile_create_ip_subnet(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_lan_profile_p	lan = (sdp_lan_profile_p) provider->data;
 	char			net[32];
 	int32_t			len;
@@ -141,7 +133,7 @@ lan_profile_create_ip_subnet(
 static int32_t
 lan_profile_data_valid(uint8_t const *data, uint32_t datalen)
 {
-	sdp_lan_profile_t const *lan = (sdp_lan_profile_t const *) data;
+	sdp_lan_profile_p	lan = (sdp_lan_profile_p) data;
 
 	if (lan->server_channel < 1 ||
 	    lan->server_channel > 30 ||
@@ -171,16 +163,10 @@ static attr_t	lan_profile_attrs[] = {
 	{ 0, NULL } /* end entry */
 };
 
-static uint16_t lan_profile_uuids[] = {
-	SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
-	SDP_UUID_PROTOCOL_L2CAP,
-	SDP_UUID_PROTOCOL_RFCOMM,
-};
-
 profile_t	lan_profile_descriptor = {
-	lan_profile_uuids,
-	sizeof(lan_profile_uuids),
+	SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
 	sizeof(sdp_lan_profile_t),
 	lan_profile_data_valid,
 	(attr_t const * const) &lan_profile_attrs
 };
+
diff --git a/usr.sbin/sdpd/log.c b/usr.sbin/sdpd/log.c
index 33f9bf10ab..54aff4a785 100644
--- a/usr.sbin/sdpd/log.c
+++ b/usr.sbin/sdpd/log.c
@@ -1,6 +1,3 @@
-/* $NetBSD: log.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/log.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * log.c
  *
@@ -28,16 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: log.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/log.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: log.c,v 1.1 2004/01/07 23:15:00 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/log.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <sys/types.h>
 #include <stdarg.h>
 #include <syslog.h>
 
-#include "log.h"
-
 void
 log_open(char const *prog, int32_t log2stderr)
 {
@@ -129,3 +124,4 @@ log_debug(char const *message, ...)
 	vsyslog(LOG_DEBUG, message, ap);
 	va_end(ap);
 }
+
diff --git a/usr.sbin/sdpd/log.h b/usr.sbin/sdpd/log.h
index 5c829661c1..2ba3ba1ed4 100644
--- a/usr.sbin/sdpd/log.h
+++ b/usr.sbin/sdpd/log.h
@@ -1,6 +1,3 @@
-/* $NetBSD: log.h,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/log.h,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * log.h
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: log.h,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/log.h,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: log.h,v 1.1 2004/01/07 23:15:00 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/log.h 124758 2004-01-20 20:48:26Z emax $
  */
 
 #ifndef _LOG_H_
@@ -37,13 +34,14 @@
 
 void	log_open	(char const *prog, int32_t log2stderr);
 void	log_close	(void);
-void	log_emerg	(char const *message, ...) __printflike(1, 2);
-void	log_alert	(char const *message, ...) __printflike(1, 2);
-void	log_crit	(char const *message, ...) __printflike(1, 2);
-void	log_err		(char const *message, ...) __printflike(1, 2);
-void	log_warning	(char const *message, ...) __printflike(1, 2);
-void	log_notice	(char const *message, ...) __printflike(1, 2);
-void	log_info	(char const *message, ...) __printflike(1, 2);
-void	log_debug	(char const *message, ...) __printflike(1, 2);
+void	log_emerg	(char const *message, ...);
+void	log_alert	(char const *message, ...);
+void	log_crit	(char const *message, ...);
+void	log_err		(char const *message, ...);
+void	log_warning	(char const *message, ...);
+void	log_notice	(char const *message, ...);
+void	log_info	(char const *message, ...);
+void	log_debug	(char const *message, ...);
 
 #endif /* ndef _LOG_H_ */
+
diff --git a/usr.sbin/sdpd/main.c b/usr.sbin/sdpd/main.c
index 50da99a716..054a0fc872 100644
--- a/usr.sbin/sdpd/main.c
+++ b/usr.sbin/sdpd/main.c
@@ -1,6 +1,3 @@
-/* $NetBSD: main.c,v 1.3 2007/03/18 15:53:55 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/main.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * main.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: main.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/main.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: main.c,v 1.8 2004/01/13 19:31:54 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/main.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <sys/select.h>
@@ -54,7 +51,7 @@
 
 #define	SDPD			"sdpd"
 
-static int32_t	drop_root	(char const *user, char const *group);
+static int32_t 	drop_root	(char const *user, char const *group);
 static void	sighandler	(int32_t s);
 static void	usage		(void);
 
@@ -69,12 +66,11 @@ main(int argc, char *argv[])
 {
 	server_t		 server;
 	char const		*control = SDP_LOCAL_PATH;
-	char const		*user = "_sdpd", *group = "_sdpd";
-	char const		*sgroup = NULL;
+	char const		*user = "nobody", *group = "nobody";
 	int32_t			 detach = 1, opt;
 	struct sigaction	 sa;
 
-	while ((opt = getopt(argc, argv, "c:dG:g:hu:")) != -1) {
+	while ((opt = getopt(argc, argv, "c:dg:hu:")) != -1) {
 		switch (opt) {
 		case 'c': /* control */
 			control = optarg;
@@ -84,10 +80,6 @@ main(int argc, char *argv[])
 			detach = 0;
 			break;
 
-		case 'G': /* super group */
-			sgroup = optarg;
-			break;
-
 		case 'g': /* group */
 			group = optarg;
 			break;
@@ -120,19 +112,19 @@ main(int argc, char *argv[])
 	    sigaction(SIGHUP,  &sa, NULL) < 0 ||
 	    sigaction(SIGINT,  &sa, NULL) < 0) {
 		log_crit("Could not install signal handlers. %s (%d)",
-			strerror(errno), errno);
+			strerror(errno), errno); 
 		exit(1);
 	}
 
 	sa.sa_handler = SIG_IGN;
 	if (sigaction(SIGPIPE, &sa, NULL) < 0) {
 		log_crit("Could not install signal handlers. %s (%d)",
-			strerror(errno), errno);
+			strerror(errno), errno); 
 		exit(1);
 	}
 
 	/* Initialize server */
-	if (server_init(&server, control, sgroup) < 0)
+	if (server_init(&server, control) < 0)
 		exit(1);
 
 	if ((user != NULL || group != NULL) && drop_root(user, group) < 0)
@@ -234,10 +226,10 @@ usage(void)
 "Where options are:\n" \
 "	-c	specify control socket name (default %s)\n" \
 "	-d	do not detach (run in foreground)\n" \
-"	-G grp	allow privileges to group\n" \
 "	-g grp	specify group\n" \
 "	-h	display usage and exit\n" \
 "	-u usr	specify user\n",
 		SDPD, SDP_LOCAL_PATH);
 	exit(255);
 }
+
diff --git a/usr.sbin/sdpd/nap.c b/usr.sbin/sdpd/nap.c
new file mode 100644
index 0000000000..d8b76c0e97
--- /dev/null
+++ b/usr.sbin/sdpd/nap.c
@@ -0,0 +1,209 @@
+/*
+ * nap.c
+ */
+
+/*-
+ * Copyright (c) 2008 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: nap.c,v 1.1 2008/03/11 00:02:42 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/nap.c 177358 2008-03-18 18:21:39Z emax $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+nap_profile_create_service_class_id_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static uint16_t	service_classes[] = {
+		SDP_SERVICE_CLASS_NAP
+	};
+
+	return (common_profile_create_service_class_id_list(
+			buf, eob,
+			(uint8_t const *) service_classes,
+			sizeof(service_classes)));
+}
+
+static int32_t
+nap_profile_create_bluetooth_profile_descriptor_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static uint16_t	profile_descriptor_list[] = {
+		SDP_SERVICE_CLASS_NAP,
+		0x0100
+	};
+
+	return (common_profile_create_bluetooth_profile_descriptor_list(
+			buf, eob,
+			(uint8_t const *) profile_descriptor_list,
+			sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+nap_profile_create_service_name(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static char	service_name[] = "Network Access Point";
+
+	return (common_profile_create_string8(
+			buf, eob,
+			(uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+nap_profile_create_service_description(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static char	service_descr[] = "Personal Ad-hoc Network Service";
+
+	return (common_profile_create_string8(
+			buf, eob,
+			(uint8_t const *) service_descr,
+			strlen(service_descr)));
+}
+
+static int32_t
+nap_profile_create_protocol_descriptor_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data; 
+	sdp_nap_profile_p	nap = (sdp_nap_profile_p) provider->data; 
+
+	return (bnep_profile_create_protocol_descriptor_list(
+			buf, eob, (uint8_t const *) &nap->psm,
+			sizeof(nap->psm))); 
+}
+
+static int32_t
+nap_profile_create_security_description(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data; 
+	sdp_nap_profile_p	nap = (sdp_nap_profile_p) provider->data; 
+
+	return (bnep_profile_create_security_description(buf, eob,
+			(uint8_t const *) &nap->security_description,
+			sizeof(nap->security_description)));
+}
+
+static int32_t
+nap_profile_create_net_access_type(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data; 
+	sdp_nap_profile_p	nap = (sdp_nap_profile_p) provider->data; 
+
+	if (buf + 3 > eob)
+		return (-1);
+
+	SDP_PUT8(SDP_DATA_UINT16, buf);
+	SDP_PUT16(nap->net_access_type, buf);
+
+	return (3);
+}
+
+static int32_t
+nap_profile_create_max_net_access_rate(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data; 
+	sdp_nap_profile_p	nap = (sdp_nap_profile_p) provider->data; 
+
+	if (buf + 3 > eob)
+		return (-1);
+
+	SDP_PUT8(SDP_DATA_UINT16, buf);
+	SDP_PUT16(nap->max_net_access_rate, buf);
+
+	return (3);
+}
+
+static int32_t
+nap_profile_create_service_availability(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data; 
+	sdp_nap_profile_p	nap = (sdp_nap_profile_p) provider->data; 
+
+	return (common_profile_create_service_availability(buf, eob,
+			&nap->load_factor, 1));
+}
+
+static int32_t
+nap_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+	sdp_nap_profile_p	nap = (sdp_nap_profile_p) data;
+
+	return ((nap->psm == 0)? 0 : 1);
+}
+
+static attr_t	nap_profile_attrs[] = {
+	{ SDP_ATTR_SERVICE_RECORD_HANDLE,
+	  common_profile_create_service_record_handle },
+	{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
+	  nap_profile_create_service_class_id_list },
+	{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+	  nap_profile_create_protocol_descriptor_list },
+	{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+	  common_profile_create_language_base_attribute_id_list },
+	{ SDP_ATTR_SERVICE_AVAILABILITY,
+	  nap_profile_create_service_availability },
+	{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+	  nap_profile_create_bluetooth_profile_descriptor_list },
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET, 
+	  nap_profile_create_service_name },
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET, 
+	  nap_profile_create_service_description },
+	{ SDP_ATTR_SECURITY_DESCRIPTION, 
+	  nap_profile_create_security_description },
+	{ SDP_ATTR_NET_ACCESS_TYPE, 
+	  nap_profile_create_net_access_type },
+	{ SDP_ATTR_MAX_NET_ACCESS_RATE, 
+	  nap_profile_create_max_net_access_rate },
+	{ 0, NULL } /* end entry */
+};
+
+profile_t	nap_profile_descriptor = {
+	SDP_SERVICE_CLASS_NAP,
+	sizeof(sdp_nap_profile_t),
+	nap_profile_data_valid,
+	(attr_t const * const) &nap_profile_attrs
+};
+
diff --git a/usr.sbin/sdpd/opush.c b/usr.sbin/sdpd/opush.c
index 24c8a30b81..bd20e74bef 100644
--- a/usr.sbin/sdpd/opush.c
+++ b/usr.sbin/sdpd/opush.c
@@ -1,6 +1,3 @@
-/* $NetBSD: opush.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/opush.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * opush.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: opush.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/opush.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: opush.c,v 1.6 2004/01/13 19:31:54 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/opush.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <sys/queue.h>
@@ -87,12 +84,12 @@ opush_profile_create_protocol_descriptor_list(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_opush_profile_p	opush = (sdp_opush_profile_p) provider->data;
 
 	return (obex_profile_create_protocol_descriptor_list(
 			buf, eob,
-			(uint8_t const *) &opush->server_channel, 1));
+			(uint8_t const *) &opush->server_channel, 1)); 
 }
 
 static int32_t
@@ -100,7 +97,7 @@ opush_profile_create_supported_formats_list(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_opush_profile_p	opush = (sdp_opush_profile_p) provider->data;
 
 	return (obex_profile_create_supported_formats_list(
@@ -127,17 +124,10 @@ static attr_t	opush_profile_attrs[] = {
 	{ 0, NULL } /* end entry */
 };
 
-static uint16_t opush_profile_uuids[] = {
-	SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
-	SDP_UUID_PROTOCOL_L2CAP,
-	SDP_UUID_PROTOCOL_RFCOMM,
-	SDP_UUID_PROTOCOL_OBEX,
-};
-
 profile_t	opush_profile_descriptor = {
-	opush_profile_uuids,
-	sizeof(opush_profile_uuids),
+	SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
 	sizeof(sdp_opush_profile_t),
 	obex_profile_data_valid,
 	(attr_t const * const) &opush_profile_attrs
 };
+
diff --git a/usr.sbin/sdpd/panu.c b/usr.sbin/sdpd/panu.c
new file mode 100644
index 0000000000..f477c4bc19
--- /dev/null
+++ b/usr.sbin/sdpd/panu.c
@@ -0,0 +1,172 @@
+/*
+ * panu.c
+ */
+
+/*-
+ * Copyright (c) 2008 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * 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.
+ *
+ * $Id: panu.c,v 1.1 2008/03/11 00:02:42 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/panu.c 177364 2008-03-19 00:06:30Z emax $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+panu_profile_create_service_class_id_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static uint16_t	service_classes[] = {
+		SDP_SERVICE_CLASS_PANU
+	};
+
+	return (common_profile_create_service_class_id_list(
+			buf, eob,
+			(uint8_t const *) service_classes,
+			sizeof(service_classes)));
+}
+
+static int32_t
+panu_profile_create_bluetooth_profile_descriptor_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static uint16_t	profile_descriptor_list[] = {
+		SDP_SERVICE_CLASS_PANU,
+		0x0100
+	};
+
+	return (common_profile_create_bluetooth_profile_descriptor_list(
+			buf, eob,
+			(uint8_t const *) profile_descriptor_list,
+			sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+panu_profile_create_service_name(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static char	service_name[] = "Personal Ad-hoc User Service";
+
+	return (common_profile_create_string8(
+			buf, eob,
+			(uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+panu_profile_create_service_description(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static char	service_descr[] =
+				"Personal Ad-hoc User Service";
+
+	return (common_profile_create_string8(
+			buf, eob,
+			(uint8_t const *) service_descr,
+			strlen(service_descr)));
+}
+
+static int32_t
+panu_profile_create_protocol_descriptor_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data;
+	sdp_panu_profile_p	panu = (sdp_panu_profile_p) provider->data;
+
+	return (bnep_profile_create_protocol_descriptor_list(
+			buf, eob, (uint8_t const *) &panu->psm,
+			sizeof(panu->psm))); 
+}
+
+static int32_t
+panu_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+	sdp_panu_profile_p	panu = (sdp_panu_profile_p) data;
+
+	return ((panu->psm == 0)? 0 : 1);
+}
+
+static int32_t
+panu_profile_create_service_availability(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data;
+	sdp_panu_profile_p	panu = (sdp_panu_profile_p) provider->data;
+
+	return (common_profile_create_service_availability( buf, eob,
+			&panu->load_factor, 1));
+}
+
+static int32_t
+panu_profile_create_security_description(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	provider_p		provider = (provider_p) data;
+	sdp_panu_profile_p	panu = (sdp_panu_profile_p) provider->data;
+
+	return (bnep_profile_create_security_description(buf, eob,
+			(uint8_t const *) &panu->security_description,
+			sizeof(panu->security_description)));
+}
+
+static attr_t	panu_profile_attrs[] = {
+	{ SDP_ATTR_SERVICE_RECORD_HANDLE,
+	  common_profile_create_service_record_handle },
+	{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
+	  panu_profile_create_service_class_id_list },
+	{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+	  panu_profile_create_protocol_descriptor_list },
+	{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+	  common_profile_create_language_base_attribute_id_list },
+	{ SDP_ATTR_SERVICE_AVAILABILITY,
+	  panu_profile_create_service_availability },
+	{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+	  panu_profile_create_bluetooth_profile_descriptor_list },
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET, 
+	  panu_profile_create_service_name },
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET, 
+	  panu_profile_create_service_description },
+	{ SDP_ATTR_SECURITY_DESCRIPTION, 
+	  panu_profile_create_security_description },
+	{ 0, NULL } /* end entry */
+};
+
+profile_t	panu_profile_descriptor = {
+	SDP_SERVICE_CLASS_PANU,
+	sizeof(sdp_panu_profile_t),
+	panu_profile_data_valid,
+	(attr_t const * const) &panu_profile_attrs
+};
+
diff --git a/usr.sbin/sdpd/profile.c b/usr.sbin/sdpd/profile.c
index c1d33a5d16..bc6773e04a 100644
--- a/usr.sbin/sdpd/profile.c
+++ b/usr.sbin/sdpd/profile.c
@@ -1,9 +1,8 @@
-/* $NetBSD: profile.c,v 1.4 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/profile.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * profile.c
- *
+ */
+
+/*-
  * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
  * All rights reserved.
  *
@@ -28,12 +27,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: profile.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/profile.c,v 1.2 2004/07/28 07:15:44 kan Exp $
+ * $Id: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/profile.c 177358 2008-03-18 18:21:39Z emax $
  */
 
 #include <sys/queue.h>
-#include <sys/utsname.h>
 #include <bluetooth.h>
 #include <sdp.h>
 #include <string.h>
@@ -49,30 +47,32 @@ profile_get_descriptor(uint16_t uuid)
 {
 	extern	profile_t	dun_profile_descriptor;
 	extern	profile_t	ftrn_profile_descriptor;
-	extern  profile_t	hf_profile_descriptor;
-	extern  profile_t	hset_profile_descriptor;
 	extern	profile_t	irmc_profile_descriptor;
 	extern	profile_t	irmc_command_profile_descriptor;
 	extern	profile_t	lan_profile_descriptor;
 	extern	profile_t	opush_profile_descriptor;
 	extern	profile_t	sp_profile_descriptor;
+	extern	profile_t	nap_profile_descriptor;
+	extern	profile_t	gn_profile_descriptor;
+	extern	profile_t	panu_profile_descriptor;
 
 	static const profile_p	profiles[] = {
 		&dun_profile_descriptor,
 		&ftrn_profile_descriptor,
-		&hf_profile_descriptor,
-		&hset_profile_descriptor,
 		&irmc_profile_descriptor,
 		&irmc_command_profile_descriptor,
 		&lan_profile_descriptor,
 		&opush_profile_descriptor,
-		&sp_profile_descriptor
+		&sp_profile_descriptor,
+		&nap_profile_descriptor,
+		&gn_profile_descriptor,
+		&panu_profile_descriptor
 	};
 
 	int32_t			i;
 
 	for (i = 0; i < sizeof(profiles)/sizeof(profiles[0]); i++)
-		if (profiles[i]->uuid[0] == uuid)
+		if (profiles[i]->uuid == uuid)
 			return (profiles[i]);
 
 	return (NULL);
@@ -85,7 +85,7 @@ profile_get_descriptor(uint16_t uuid)
 profile_attr_create_p
 profile_get_attr(const profile_p profile, uint16_t attr)
 {
-	attr_t const	*ad = (attr_t const *) profile->attrs;
+	attr_p	ad = (attr_p) profile->attrs;
 
 	for (; ad->create != NULL; ad ++)
 		if (ad->attr == attr)
@@ -107,7 +107,7 @@ common_profile_create_service_record_handle(
 		return (-1);
 
 	SDP_PUT8(SDP_DATA_UINT32, buf);
-	SDP_PUT32(((provider_t const *) data)->handle, buf);
+	SDP_PUT32(((provider_p) data)->handle, buf);
 
 	return (5);
 }
@@ -156,7 +156,7 @@ common_profile_create_bluetooth_profile_descriptor_list(
 		uint8_t const *data, uint32_t datalen)
 {
 	int32_t	len = 8 * (datalen >>= 2);
-
+	
 	if (len <= 0 || len > 0xff || buf + 2 + len > eob)
 		return (-1);
 
@@ -202,15 +202,15 @@ common_profile_create_language_base_attribute_id_list(
 	SDP_PUT8(SDP_DATA_UINT16, buf);
 	SDP_PUT16(((0x65 << 8) | 0x6e), buf);
 
-	/*
-	 * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106
+	/* 
+	 * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106 
 	 * (http://www.iana.org/assignments/character-sets)
 	 */
 
 	SDP_PUT8(SDP_DATA_UINT16, buf);
 	SDP_PUT16(106, buf);
 
-	/*
+	/* 
 	 * Offset (Primary Language Base is 0x100)
 	 */
 
@@ -221,7 +221,7 @@ common_profile_create_language_base_attribute_id_list(
 }
 
 /*
- * Use Operating System name as provider name
+ * Common provider name is "FreeBSD"
  */
 
 int32_t
@@ -229,16 +229,11 @@ common_profile_create_service_provider_name(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	struct utsname u;
-	char const *name;
-
-	if (uname(&u) < 0)
-		name = "Unknown";
-	else
-		name = u.sysname;
+	char	provider_name[] = "FreeBSD";
 
 	return (common_profile_create_string8(buf, eob,
-			(uint8_t const *)name, strlen(name)));
+			(uint8_t const *) provider_name,
+			strlen(provider_name)));
 }
 
 /*
@@ -260,6 +255,24 @@ common_profile_create_string8(
 	return (2 + datalen);
 }
 
+/*
+ * Service Availability
+ */
+
+int32_t
+common_profile_create_service_availability(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	if (datalen != 1 || buf + 2 > eob)
+		return (-1);
+
+	SDP_PUT8(SDP_DATA_UINT8, buf);
+	SDP_PUT8(data[0], buf);
+
+	return (2);
+}
+
 /*
  * seq8 len8			- 2 bytes
  *	seq8 len8		- 2 bytes
@@ -364,6 +377,16 @@ obex_profile_create_supported_formats_list(
 	return (2 + len);
 }
 
+/*
+ * do not check anything
+ */
+
+int32_t
+common_profile_always_valid(uint8_t const *data, uint32_t datalen)
+{
+	return (1);
+}
+
 /*
  * verify server channel number (the first byte in the data)
  */
@@ -378,14 +401,14 @@ common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen)
 }
 
 /*
- * verify server channel number and supported_formats_size
+ * verify server channel number and supported_formats_size 
  * sdp_opush_profile and sdp_irmc_profile
  */
 
 int32_t
 obex_profile_data_valid(uint8_t const *data, uint32_t datalen)
 {
-	sdp_opush_profile_t const *opush = (sdp_opush_profile_t const *) data;
+	sdp_opush_profile_p	opush = (sdp_opush_profile_p) data;
 
 	if (opush->server_channel < 1 ||
 	    opush->server_channel > 30 ||
@@ -395,3 +418,80 @@ obex_profile_data_valid(uint8_t const *data, uint32_t datalen)
 
 	return (1);
 }
+
+/*
+ * BNEP protocol descriptor
+ */
+
+int32_t
+bnep_profile_create_protocol_descriptor_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	/* supported protocol types */
+	uint16_t	 ptype[] = {
+		0x0800,	/* IPv4 */
+		0x0806,	/* ARP */
+#ifdef INET6
+		0x86dd,	/* IPv6 */
+#endif
+	};
+
+	uint16_t	 i, psm, version = 0x0100,
+			 nptypes = sizeof(ptype)/sizeof(ptype[0]),
+			 nptypes_size = nptypes * 3;
+
+	if (datalen != 2 || 18 + nptypes_size > 255 ||
+	    buf + 20 + nptypes_size > eob)
+		return (-1);
+
+	memcpy(&psm, data, sizeof(psm));
+
+	SDP_PUT8(SDP_DATA_SEQ8, buf);
+	SDP_PUT8(18 + nptypes_size, buf);
+
+	SDP_PUT8(SDP_DATA_SEQ8, buf);
+	SDP_PUT8(6, buf);
+	SDP_PUT8(SDP_DATA_UUID16, buf);
+	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
+	SDP_PUT8(SDP_DATA_UINT16, buf);
+	SDP_PUT16(psm, buf);
+	
+	SDP_PUT8(SDP_DATA_SEQ8, buf);
+	SDP_PUT8(8 + nptypes_size, buf);
+	SDP_PUT8(SDP_DATA_UUID16, buf);
+	SDP_PUT16(SDP_UUID_PROTOCOL_BNEP, buf);
+	SDP_PUT8(SDP_DATA_UINT16, buf);
+	SDP_PUT16(version, buf);
+	SDP_PUT8(SDP_DATA_SEQ8, buf);
+	SDP_PUT8(nptypes_size, buf);
+	for (i = 0; i < nptypes; i ++) {
+		SDP_PUT8(SDP_DATA_UINT16, buf);
+		SDP_PUT16(ptype[i], buf);
+	}
+
+	return (20 + nptypes_size);
+}
+
+/*
+ * BNEP security description
+ */
+
+int32_t
+bnep_profile_create_security_description(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	uint16_t	security_descr;
+
+	if (datalen != 2 || buf + 3 > eob)
+		return (-1);
+
+	memcpy(&security_descr, data, sizeof(security_descr));
+
+	SDP_PUT8(SDP_DATA_UINT16, buf);
+	SDP_PUT16(security_descr, buf);
+
+        return (3);
+}
+
diff --git a/usr.sbin/sdpd/profile.h b/usr.sbin/sdpd/profile.h
index 87e4b915b4..92d0734cec 100644
--- a/usr.sbin/sdpd/profile.h
+++ b/usr.sbin/sdpd/profile.h
@@ -1,9 +1,8 @@
-/* $NetBSD: profile.h,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/profile.h,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * profile.h
- *
+ */
+
+/*-
  * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
  * All rights reserved.
  *
@@ -28,8 +27,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: profile.h,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/profile.h,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: profile.h,v 1.6 2004/01/13 19:31:54 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/profile.h 177358 2008-03-18 18:21:39Z emax $
  */
 
 #ifndef _PROFILE_H_
@@ -64,8 +63,7 @@ typedef struct attr *	attr_p;
 
 struct profile
 {
-	uint16_t *		uuid;	/* profile uuid list */
-	ssize_t			usize;	/* profile uuid list size */
+	uint16_t		uuid;	/* profile uuid */
 	uint16_t		dsize;	/* profile data size */
 	profile_data_valid_p	valid;	/* profile data validator */
 	attr_t const * const	attrs;	/* supported attributes */
@@ -83,11 +81,16 @@ profile_attr_create_t	common_profile_create_bluetooth_profile_descriptor_list;
 profile_attr_create_t	common_profile_create_language_base_attribute_id_list;
 profile_attr_create_t	common_profile_create_service_provider_name;
 profile_attr_create_t	common_profile_create_string8;
+profile_attr_create_t	common_profile_create_service_availability;
 profile_attr_create_t	rfcomm_profile_create_protocol_descriptor_list;
 profile_attr_create_t	obex_profile_create_protocol_descriptor_list;
 profile_attr_create_t	obex_profile_create_supported_formats_list;
+profile_attr_create_t	bnep_profile_create_protocol_descriptor_list;
+profile_attr_create_t	bnep_profile_create_security_description;
 
+profile_data_valid_t	common_profile_always_valid;
 profile_data_valid_t	common_profile_server_channel_valid;
 profile_data_valid_t	obex_profile_data_valid;
 
 #endif /* ndef _PROFILE_H_ */
+
diff --git a/usr.sbin/sdpd/provider.c b/usr.sbin/sdpd/provider.c
index cee68ff988..0f5f4ded40 100644
--- a/usr.sbin/sdpd/provider.c
+++ b/usr.sbin/sdpd/provider.c
@@ -1,6 +1,3 @@
-/* $NetBSD: provider.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/provider.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * provider.c
  *
@@ -28,22 +25,20 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: provider.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/provider.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: provider.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/provider.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <sys/queue.h>
 #include <bluetooth.h>
-#include <sdp.h>
 #include <string.h>
 #include <stdlib.h>
 #include "profile.h"
 #include "provider.h"
-#include "uuid-private.h"
 
 static TAILQ_HEAD(, provider)	providers = TAILQ_HEAD_INITIALIZER(providers);
-static uint32_t			change_state = 0;
-static uint32_t			next_handle = 0;
+static uint32_t			change_state = 0;		
+static uint32_t			handle = 0;
 
 /*
  * Register Service Discovery provider.
@@ -78,7 +73,7 @@ provider_register_sd(int32_t fd)
 	bgd->handle = 1;
 	sd->fd = fd;
 	TAILQ_INSERT_AFTER(&providers, sd, bgd, provider_next);
-
+	
 	change_state ++;
 
 	return (0);
@@ -89,7 +84,7 @@ provider_register_sd(int32_t fd)
  */
 
 provider_p
-provider_register(profile_p const profile, bdaddr_t const *bdaddr, int32_t fd,
+provider_register(profile_p const profile, bdaddr_p const bdaddr, int32_t fd,
 	uint8_t const *data, uint32_t datalen)
 {
 	provider_p	provider = calloc(1, sizeof(*provider));
@@ -105,10 +100,10 @@ provider_register(profile_p const profile, bdaddr_t const *bdaddr, int32_t fd,
 			 * for SDP itself
 			 */
 
-			if (++ next_handle <= 1)
-				next_handle = 2;
+			if (++ handle <= 1)
+				handle = 2;
 
-			provider->handle = next_handle;
+			provider->handle = handle;
 
 			memcpy(&provider->bdaddr, bdaddr,
 				sizeof(provider->bdaddr));
@@ -199,37 +194,3 @@ provider_get_change_state(void)
 	return (change_state);
 }
 
-/*
- * Match provider to UUID list
- *
- *	all UUIDs in list must match one of the
- *	provider UUIDs or the PublicBrowseGroup
- */
-
-int
-provider_match_uuid(provider_p provider, uint128_t *uuid, int ucount)
-{
-	uint128_t puuid;
-	int num, max;
-
-	max = provider->profile->usize / sizeof(provider->profile->uuid[0]);
-
-	for (; ucount-- > 0 ; uuid++) {
-		if (memcmp(uuid, &uuid_public_browse_group, sizeof(*uuid)) == 0)
-			continue;
-
-		for (num = 0 ; ; num++) {
-			if (num == max)
-				return 0;
-
-			memcpy(&puuid, &uuid_base, sizeof(puuid));
-			puuid.b[2] = provider->profile->uuid[num] >> 8;
-			puuid.b[3] = provider->profile->uuid[num];
-
-			if (memcmp(uuid, &puuid, sizeof(*uuid)) == 0)
-				break;
-		}
-	}
-
-	return 1;
-}
diff --git a/usr.sbin/sdpd/provider.h b/usr.sbin/sdpd/provider.h
index a1eeca4a60..46f362e3ec 100644
--- a/usr.sbin/sdpd/provider.h
+++ b/usr.sbin/sdpd/provider.h
@@ -1,34 +1,3 @@
-/* $NetBSD: provider.h,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/provider.h,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
 /*
  * provider.h
  *
@@ -56,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: provider.h,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/provider.h,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: provider.h,v 1.6 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/provider.h 124758 2004-01-20 20:48:26Z emax $
  */
 
 #ifndef _PROVIDER_H_
@@ -71,7 +40,7 @@ struct profile;
 
 struct provider
 {
-	struct profile		*profile;		/* profile */
+	struct profile 		*profile;		/* profile */
 	void			*data;			/* profile data */
 	uint32_t		 handle;		/* record handle */
 	bdaddr_t		 bdaddr;		/* provider's BDADDR */
@@ -83,12 +52,13 @@ typedef struct provider		provider_t;
 typedef struct provider	*	provider_p;
 
 #define		provider_match_bdaddr(p, b) \
-	(bdaddr_any(b) || bdaddr_any(&(p)->bdaddr) || \
-	 bdaddr_same(&(p)->bdaddr, (b)))
-
+	(memcmp(b, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0 || \
+	 memcmp(&(p)->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0 || \
+	 memcmp(&(p)->bdaddr, b, sizeof(bdaddr_t)) == 0)
+	
 int32_t		provider_register_sd		(int32_t fd);
 provider_p	provider_register		(profile_p const profile,
-						 bdaddr_t const *bdaddr,
+						 bdaddr_p const bdaddr,
 						 int32_t fd,
 						 uint8_t const *data,
 						 uint32_t datalen);
@@ -102,10 +72,4 @@ provider_p	provider_get_first		(void);
 provider_p	provider_get_next		(provider_p provider);
 uint32_t	provider_get_change_state	(void);
 
-int		provider_match_uuid		(provider_p provider,
-						 uint128_t *ulist, int ucount);
-
-int32_t server_prepare_attr_list(provider_p const, uint8_t const *, uint8_t const *,
-		uint8_t *, uint8_t const *);
-
 #endif /* ndef _PROVIDER_H_ */
diff --git a/usr.sbin/sdpd/sar.c b/usr.sbin/sdpd/sar.c
index 1f3ca787c7..6bd9e1b78c 100644
--- a/usr.sbin/sdpd/sar.c
+++ b/usr.sbin/sdpd/sar.c
@@ -1,6 +1,3 @@
-/* $NetBSD: sar.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/sar.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * sar.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: sar.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/sar.c,v 1.2 2004/02/26 20:44:55 emax Exp $
+ * $Id: sar.c,v 1.2 2004/01/08 23:46:51 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/sar.c 126297 2004-02-26 20:44:55Z emax $
  */
 
 #include <sys/queue.h>
@@ -147,9 +144,9 @@ server_prepare_service_attribute_response(server_p srv, int32_t fd)
 	uint8_t const	*req = srv->req + sizeof(sdp_pdu_t);
 	uint8_t const	*req_end = req + ((sdp_pdu_p)(srv->req))->len;
 	uint8_t		*rsp = srv->fdidx[fd].rsp;
-	uint8_t const	*rsp_end = rsp + L2CAP_MTU_MAXIMUM;
+	uint8_t const	*rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
 
-	uint8_t const	*ptr = NULL;
+	uint8_t		*ptr = NULL;
 	provider_t	*provider = NULL;
 	uint32_t	 handle;
 	int32_t		 type, rsp_limit, aidlen, cslen, cs;
@@ -187,17 +184,17 @@ server_prepare_service_attribute_response(server_p srv, int32_t fd)
 
 	case SDP_DATA_SEQ32:
 		SDP_GET32(aidlen, req);
-		break;
+ 		break;
 	}
 	if (aidlen <= 0)
 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
 
-	ptr = (uint8_t const *) req + aidlen;
+	ptr = (uint8_t *) req + aidlen;
 
 	/* Get ContinuationState */
 	if (ptr + 1 > req_end)
 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
-
+		
 	SDP_GET8(cslen, ptr);
 	if (cslen != 0) {
 		if (cslen != 2 || req_end - ptr != 2)
@@ -242,7 +239,7 @@ server_prepare_service_attribute_response(server_p srv, int32_t fd)
 }
 
 /*
- * Send SDP Service [Search] Attribute Response
+ * Send SDP Service [Search] Attribute Response 
  */
 
 int32_t
@@ -314,6 +311,7 @@ server_send_service_attribute_response(server_p srv, int32_t fd)
 		srv->fdidx[fd].rsp_size = 0;
 		srv->fdidx[fd].rsp_limit = 0;
 	}
-
+	
 	return ((size < 0)? errno : 0);
 }
+
diff --git a/usr.sbin/sdpd/scr.c b/usr.sbin/sdpd/scr.c
index 4ad9031c0a..7191f6f814 100644
--- a/usr.sbin/sdpd/scr.c
+++ b/usr.sbin/sdpd/scr.c
@@ -1,6 +1,3 @@
-/* $NetBSD: scr.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/scr.c,v 1.2 2008/05/19 10:19:49 corecode Exp $ */
-
 /*
  * scr.c
  *
@@ -28,12 +25,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: scr.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/scr.c,v 1.2 2005/12/06 17:56:36 emax Exp $
+ * $Id: scr.c,v 1.1 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/scr.c 153176 2005-12-06 17:56:36Z emax $
  */
 
 #include <sys/queue.h>
-#include <sys/select.h>
 #include <bluetooth.h>
 #include <errno.h>
 #include <sdp.h>
@@ -85,7 +81,7 @@ server_prepare_service_change_response(server_p srv, int32_t fd)
 		return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
 
 	SDP_PUT16(0, rsp);
-
+	
 	/* Set reply size */
 	srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t);
 	srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
@@ -93,3 +89,4 @@ server_prepare_service_change_response(server_p srv, int32_t fd)
 
 	return (0);
 }
+
diff --git a/usr.sbin/sdpd/sd.c b/usr.sbin/sdpd/sd.c
index d45e0e8efc..21f3b79058 100644
--- a/usr.sbin/sdpd/sd.c
+++ b/usr.sbin/sdpd/sd.c
@@ -1,5 +1,3 @@
-/* $NetBSD: sd.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-
 /*
  * sd.c
  *
@@ -27,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: sd.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/sd.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: sd.c,v 1.4 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/sd.c 185320 2008-11-25 21:54:42Z emax $
  */
 
 #include <sys/queue.h>
@@ -53,6 +51,22 @@ sd_profile_create_service_class_id_list(
 			sizeof(service_classes)));
 }
 
+static int32_t
+sd_profile_create_bluetooth_profile_descriptor_list(
+		uint8_t *buf, uint8_t const * const eob,
+		uint8_t const *data, uint32_t datalen)
+{
+	static uint16_t profile_descriptor_list[] = {
+		SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER,
+		0x0100
+	};
+
+	return (common_profile_create_bluetooth_profile_descriptor_list(
+			buf, eob,
+			(uint8_t const *) profile_descriptor_list,
+			sizeof(profile_descriptor_list)));
+}
+
 static int32_t
 sd_profile_create_service_id(
 		uint8_t *buf, uint8_t const * const eob,
@@ -62,7 +76,7 @@ sd_profile_create_service_id(
 		return (-1);
 
 	/*
-	 * The ServiceID is a UUID that universally and uniquely identifies
+	 * The ServiceID is a UUID that universally and uniquely identifies 
 	 * the service instance described by the service record. This service
 	 * attribute is particularly useful if the same service is described
 	 * by service records in more than one SDP server
@@ -91,25 +105,23 @@ sd_profile_create_protocol_descriptor_list(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	if (buf + 13 > eob)
+	if (buf + 12 > eob)
 		return (-1);
 
 	SDP_PUT8(SDP_DATA_SEQ8, buf);
-	SDP_PUT8(11, buf);
+	SDP_PUT8(10, buf);
 
 	SDP_PUT8(SDP_DATA_SEQ8, buf);
-	SDP_PUT8(9, buf);
-
+	SDP_PUT8(3, buf);
 	SDP_PUT8(SDP_DATA_UUID16, buf);
 	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
 
-	SDP_PUT8(SDP_DATA_UINT16, buf);
-	SDP_PUT16(L2CAP_PSM_SDP, buf);
-
-	SDP_PUT8(SDP_DATA_UINT16, buf);
-	SDP_PUT16(1, buf); /* version */
+	SDP_PUT8(SDP_DATA_SEQ8, buf);
+	SDP_PUT8(3, buf);
+	SDP_PUT8(SDP_DATA_UUID16, buf);
+	SDP_PUT16(SDP_UUID_PROTOCOL_SDP, buf);
 
-	return (13);
+	return (12);
 }
 
 static int32_t
@@ -147,8 +159,8 @@ sd_profile_create_version_number_list(
 	SDP_PUT8(SDP_DATA_SEQ8, buf);
 	SDP_PUT8(3, buf);
 
-	/*
-	 * The VersionNumberList is a data element sequence in which each
+	/* 
+	 * The VersionNumberList is a data element sequence in which each 
 	 * element of the sequence is a version number supported by the SDP
 	 * server. A version number is a 16-bit unsigned integer consisting
 	 * of two fields. The higher-order 8 bits contain the major version
@@ -184,13 +196,15 @@ static attr_t	sd_profile_attrs[] = {
 	  common_profile_create_service_record_handle },
 	{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
 	  sd_profile_create_service_class_id_list },
+	{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+	  sd_profile_create_bluetooth_profile_descriptor_list },
 	{ SDP_ATTR_SERVICE_ID,
 	  sd_profile_create_service_id },
 	{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
 	  common_profile_create_language_base_attribute_id_list },
-	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET, 
 	  sd_profile_create_service_name },
-	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
+	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET, 
 	  sd_profile_create_service_name },
 	{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET,
 	  common_profile_create_service_provider_name },
@@ -205,15 +219,10 @@ static attr_t	sd_profile_attrs[] = {
 	{ 0, NULL } /* end entry */
 };
 
-static uint16_t sd_profile_uuids[] = {
-	SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER,
-	SDP_UUID_PROTOCOL_L2CAP,
-};
-
 profile_t	sd_profile_descriptor = {
-	sd_profile_uuids,
-	sizeof(sd_profile_uuids),
+	SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER,
 	0,
-	NULL,
+	(profile_data_valid_p) NULL,
 	(attr_t const * const) &sd_profile_attrs
 };
+
diff --git a/usr.sbin/sdpd/sdpd.8 b/usr.sbin/sdpd/sdpd.8
index d4369792b9..935de684d5 100644
--- a/usr.sbin/sdpd/sdpd.8
+++ b/usr.sbin/sdpd/sdpd.8
@@ -1,5 +1,3 @@
-.\" $NetBSD: sdpd.8,v 1.3 2007/03/18 15:53:55 plunky Exp $
-.\"
 .\" Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
 .\" All rights reserved.
 .\"
@@ -24,8 +22,8 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $Id: sdpd.8,v 1.2 2007/11/30 07:39:37 griffin Exp $
-.\" $FreeBSD: src/usr.sbin/bluetooth/sdpd/sdpd.8,v 1.5 2005/12/06 17:56:36 emax Exp $
+.\" $Id: sdpd.8,v 1.1 2004/01/13 19:31:54 max Exp $
+.\" $FreeBSD: head/usr.sbin/bluetooth/sdpd/sdpd.8 267668 2014-06-20 09:57:27Z bapt $
 .\"
 .Dd January 13, 2004
 .Dt SDPD 8
@@ -37,7 +35,6 @@
 .Nm
 .Op Fl dh
 .Op Fl c Ar path
-.Op Fl G Ar group
 .Op Fl g Ar group
 .Op Fl u Ar user
 .Sh DESCRIPTION
@@ -65,7 +62,7 @@ performed over the control socket.
 It is possible to query entire content of the
 .Nm
 Service Database with
-.Xr sdpquery 1
+.Xr sdpcontrol 8
 by issuing
 .Cm browse
 command on the control socket.
@@ -78,12 +75,6 @@ Do not detach from the controlling terminal.
 Specify path to the control socket.
 The default path is
 .Pa /var/run/sdp .
-.It Fl G Ar group
-Grant permission to members of the
-.Ar group
-to modify the
-.Nm
-Service Database.
 .It Fl g Ar group
 Specifies the group the
 .Nm
@@ -93,7 +84,7 @@ This only works if
 .Nm
 was started as root.
 The default group name is
-.Dq Li _sdpd .
+.Dq Li nobody .
 .It Fl h
 Display usage message and exit.
 .It Fl u Ar user
@@ -105,7 +96,7 @@ This only works if
 .Nm
 was started as root.
 The default user name is
-.Dq Li _sdpd .
+.Dq Li nobody .
 .El
 .Sh CAVEATS
 The
@@ -123,11 +114,10 @@ Requests to register, remove or change service can only be made via the
 control socket.
 The
 .Nm
-daemon will check the peer's credentials and will only accept the request
-when the peer is the superuser, of if the peer is a member of the group
-specified with the
-.Fl G
-option.
+daemon will check peer's credentials and will only accept the request if
+the application has the same effective user ID as the
+.Dq Li root
+user ID.
 .Pp
 The
 .Nm
@@ -141,21 +131,8 @@ as RFCOMM channels etc., before registering the service.
 .It Pa /var/run/sdp
 .El
 .Sh SEE ALSO
-.Xr sdpquery 1 ,
-.Xr sdp 3
-.Sh HISTORY
-The
-.Nm
-daemon first appeared in
-.Fx 5.3
-and was imported into
-.Nx 4.0
-by
-.An Iain Hibbert
-under the sponsorship of
-.An Itronix, Inc.
-It was imported into
-.Dx 1.11 .
+.Xr sdp 3 ,
+.Xr sdpcontrol 8
 .Sh AUTHORS
 .An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
 .Sh BUGS
diff --git a/usr.sbin/sdpd/server.c b/usr.sbin/sdpd/server.c
index a012c2edb2..7079042f64 100644
--- a/usr.sbin/sdpd/server.c
+++ b/usr.sbin/sdpd/server.c
@@ -1,33 +1,3 @@
-/* $NetBSD: server.c,v 1.3 2007/03/18 10:00:42 plunky Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
 /*
  * server.c
  *
@@ -55,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: server.c,v 1.1.1.1 2007/11/20 11:56:11 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/server.c,v 1.2 2005/12/06 17:56:36 emax Exp $
+ * $Id: server.c,v 1.6 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/server.c 229655 2012-01-05 21:36:45Z uqs $
  */
 
 #include <sys/param.h>
@@ -65,13 +35,11 @@
 #include <sys/queue.h>
 #include <sys/ucred.h>
 #include <sys/un.h>
-#include <sys/uio.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <assert.h>
 #include <bluetooth.h>
 #include <errno.h>
-#include <grp.h>
 #include <pwd.h>
 #include <sdp.h>
 #include <stdio.h>
@@ -88,30 +56,24 @@ static int32_t	server_process_request		(server_p srv, int32_t fd);
 static int32_t	server_send_error_response	(server_p srv, int32_t fd,
 						 uint16_t error);
 static void	server_close_fd			(server_p srv, int32_t fd);
-#if 0 /* XXX */
-static int	server_auth_check		(server_p srv, struct sockcred *cred);
-static int 	server_auth_check		(server_p srv, struct cmsgcred *cred);
-#endif
 
 /*
  * Initialize server
  */
 
 int32_t
-server_init(server_p srv, char const *control, char const *sgroup)
+server_init(server_p srv, char const *control)
 {
 	struct sockaddr_un	un;
-	struct sockaddr_bt	l2;
-	socklen_t		size;
+	struct sockaddr_l2cap	l2;
 	int32_t			unsock, l2sock;
+	socklen_t		size;
 	uint16_t		imtu;
-	int			opt;
 
 	assert(srv != NULL);
 	assert(control != NULL);
 
-	memset(srv, 0, sizeof(struct server));
-	srv->sgroup = sgroup;
+	memset(srv, 0, sizeof(*srv));
 
 	/* Open control socket */
 	if (unlink(control) < 0 && errno != ENOENT) {
@@ -127,11 +89,6 @@ server_init(server_p srv, char const *control, char const *sgroup)
 		return (-1);
 	}
 
-	opt = 1;
-#if 0
-	if (setsockopt(unsock, 0, LOCAL_CREDS, &opt, sizeof(opt)) < 0)
-		log_crit("Warning: No credential checks on control socket");
-#endif
 	memset(&un, 0, sizeof(un));
 	un.sun_len = sizeof(un);
 	un.sun_family = AF_LOCAL;
@@ -159,7 +116,7 @@ server_init(server_p srv, char const *control, char const *sgroup)
 	}
 
 	/* Open L2CAP socket */
-	l2sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+	l2sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
 	if (l2sock < 0) {
 		log_crit("Could not create L2CAP socket. %s (%d)",
 			strerror(errno), errno);
@@ -168,7 +125,7 @@ server_init(server_p srv, char const *control, char const *sgroup)
 	}
 
 	size = sizeof(imtu);
-        if (getsockopt(l2sock, BTPROTO_L2CAP, SO_L2CAP_IMTU, &imtu, &size) < 0) {
+        if (getsockopt(l2sock, SOL_L2CAP, SO_L2CAP_IMTU, &imtu, &size) < 0) {
 		log_crit("Could not get L2CAP IMTU. %s (%d)",
 			strerror(errno), errno);
 		close(unsock);
@@ -177,10 +134,10 @@ server_init(server_p srv, char const *control, char const *sgroup)
         }
 
 	memset(&l2, 0, sizeof(l2));
-	l2.bt_len = sizeof(l2);
-	l2.bt_family = AF_BLUETOOTH;
-	l2.bt_psm = L2CAP_PSM_SDP;
-	bdaddr_copy(&l2.bt_bdaddr, BDADDR_ANY);
+	l2.l2cap_len = sizeof(l2);
+	l2.l2cap_family = AF_BLUETOOTH;
+	memcpy(&l2.l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2.l2cap_bdaddr));
+	l2.l2cap_psm = htole16(NG_L2CAP_PSM_SDP);
 
 	if (bind(l2sock, (struct sockaddr *) &l2, sizeof(l2)) < 0) {
 		log_crit("Could not bind L2CAP socket. %s (%d)",
@@ -235,7 +192,7 @@ server_init(server_p srv, char const *control, char const *sgroup)
 
 	FD_ZERO(&srv->fdset);
 	srv->maxfd = (unsock > l2sock)? unsock : l2sock;
-
+	
 	FD_SET(unsock, &srv->fdset);
 	srv->fdidx[unsock].valid = 1;
 	srv->fdidx[unsock].server = 1;
@@ -322,7 +279,7 @@ server_do(server_p srv)
 	}
 
 	return (0);
-
+	
 }
 
 /*
@@ -333,9 +290,9 @@ static void
 server_accept_client(server_p srv, int32_t fd)
 {
 	uint8_t		*rsp = NULL;
-	socklen_t	 size;
-	int32_t		 cfd;
+	int32_t		 cfd, priv;
 	uint16_t	 omtu;
+	socklen_t	 size;
 
 	do {
 		cfd = accept(fd, NULL, NULL);
@@ -351,10 +308,12 @@ server_accept_client(server_p srv, int32_t fd)
 	assert(!FD_ISSET(cfd, &srv->fdset));
 	assert(!srv->fdidx[cfd].valid);
 
+	priv = 0;
+
 	if (!srv->fdidx[fd].control) {
 		/* Get local BD_ADDR */
 		size = sizeof(srv->req_sa);
-		if (getsockname(cfd,(struct sockaddr*)&srv->req_sa, &size) < 0) {
+		if (getsockname(cfd,(struct sockaddr*)&srv->req_sa,&size) < 0) {
 			log_err("Could not get local BD_ADDR. %s (%d)",
 				strerror(errno), errno);
 			close(cfd);
@@ -363,7 +322,7 @@ server_accept_client(server_p srv, int32_t fd)
 
 		/* Get outgoing MTU */
 		size = sizeof(omtu);
-	        if (getsockopt(cfd, BTPROTO_L2CAP, SO_L2CAP_OMTU, &omtu, &size) < 0) {
+	        if (getsockopt(cfd,SOL_L2CAP,SO_L2CAP_OMTU,&omtu,&size) < 0) {
 			log_err("Could not get L2CAP OMTU. %s (%d)",
 				strerror(errno), errno);
 			close(cfd);
@@ -375,25 +334,49 @@ server_accept_client(server_p srv, int32_t fd)
 		 * The minimum L2CAP MTU is 43 bytes. That means we need
 		 * 65536 / 43 = ~1524 chunks to transfer maximum packet
 		 * size with minimum MTU. The "rsp_cs" field in fd_idx_t
-		 * is 11 bit wide that gives us upto 2048 chunks.
+		 * is 11 bits wide, which gives us up to 2048 chunks.
 		 */
 
-		if (omtu < L2CAP_MTU_MINIMUM) {
+		if (omtu < NG_L2CAP_MTU_MINIMUM) {
 			log_err("L2CAP OMTU is too small (%d bytes)", omtu);
 			close(cfd);
 			return;
 		}
 	} else {
-		bdaddr_copy(&srv->req_sa.bt_bdaddr, BDADDR_ANY);
+		struct xucred	 cr;
+		struct passwd	*pw;
+
+		/* Get peer's credentials */
+		memset(&cr, 0, sizeof(cr));
+		size = sizeof(cr);
+
+		if (getsockopt(cfd, 0, LOCAL_PEERCRED, &cr, &size) < 0) {
+			log_err("Could not get peer's credentials. %s (%d)",
+				strerror(errno), errno);
+			close(cfd);
+			return;
+		}
+
+		/* Check credentials */
+		pw = getpwuid(cr.cr_uid);
+		if (pw != NULL)
+			priv = (strcmp(pw->pw_name, "root") == 0);
+		else
+			log_warning("Could not verify credentials for uid %d",
+				cr.cr_uid);
+
+		memcpy(&srv->req_sa.l2cap_bdaddr, NG_HCI_BDADDR_ANY,
+			sizeof(srv->req_sa.l2cap_bdaddr));
+
 		omtu = srv->fdidx[fd].omtu;
 	}
 
 	/*
-	 * Allocate buffer. This is an overkill, but we can not know how
+	 * Allocate buffer. This is an overkill, but we can not know how 
 	 * big our reply is going to be.
 	 */
 
-	rsp = (uint8_t *) calloc(L2CAP_MTU_MAXIMUM, sizeof(rsp[0]));
+	rsp = (uint8_t *) calloc(NG_L2CAP_MTU_MAXIMUM, sizeof(rsp[0]));
 	if (rsp == NULL) {
 		log_crit("Could not allocate response buffer");
 		close(cfd);
@@ -407,7 +390,7 @@ server_accept_client(server_p srv, int32_t fd)
 	srv->fdidx[cfd].valid = 1;
 	srv->fdidx[cfd].server = 0;
 	srv->fdidx[cfd].control = srv->fdidx[fd].control;
-	srv->fdidx[cfd].priv = 0;
+	srv->fdidx[cfd].priv = priv;
 	srv->fdidx[cfd].rsp_cs = 0;
 	srv->fdidx[cfd].rsp_size = 0;
 	srv->fdidx[cfd].rsp_limit = 0;
@@ -422,14 +405,8 @@ server_accept_client(server_p srv, int32_t fd)
 static int32_t
 server_process_request(server_p srv, int32_t fd)
 {
-	uint8_t		ctl[128];
 	sdp_pdu_p	pdu = (sdp_pdu_p) srv->req;
-	struct msghdr	msg;
-	struct iovec	iov;
 	int32_t		len, error;
-#if 0 /* XXX */
-	struct cmsghdr	*cmsg;
-#endif
 
 	assert(srv->imtu > 0);
 	assert(srv->req != NULL);
@@ -437,21 +414,10 @@ server_process_request(server_p srv, int32_t fd)
 	assert(srv->fdidx[fd].valid);
 	assert(!srv->fdidx[fd].server);
 	assert(srv->fdidx[fd].rsp != NULL);
-	assert(srv->fdidx[fd].omtu >= L2CAP_MTU_MINIMUM);
-
-	iov.iov_base = srv->req;
-	iov.iov_len = srv->imtu;
-
-	msg.msg_name = NULL;
-	msg.msg_namelen = 0;
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
-	msg.msg_control = ctl;
-	msg.msg_controllen = sizeof(ctl);
-	msg.msg_flags = 0;
+	assert(srv->fdidx[fd].omtu >= NG_L2CAP_MTU_MINIMUM);
 
 	do {
-		len = recvmsg(fd, &msg, 0);
+		len = read(fd, srv->req, srv->imtu);
 	} while (len < 0 && errno == EINTR);
 
 	if (len < 0) {
@@ -466,25 +432,8 @@ server_process_request(server_p srv, int32_t fd)
 		return (-1);
 	}
 
-#if 0 /* XXX */
-	if ((cmsg = CMSG_FIRSTHDR(&msg)) != NULL
-	    && cmsg->cmsg_level == SOL_SOCKET
-	    && cmsg->cmsg_type == SCM_CREDS
-#if 0
-	    && cmsg->cmsg_len >= CMSG_LEN(SOCKCREDSIZE(0))
-#endif
-)
-	    	srv->fdidx[fd].priv = 
-		    server_auth_check(srv, (struct cmsgcred *)CMSG_DATA(cmsg));
-#if 0
-		    server_auth_check(srv, (struct sockcred *)CMSG_DATA(cmsg));
-#endif
-#else
-	srv->fdidx[fd].priv = 1;
-#endif
-
-	if (len >= sizeof(*pdu)
-	    && (sizeof(*pdu) + (pdu->len = ntohs(pdu->len))) == len) {
+	if (len >= sizeof(*pdu) &&
+	    sizeof(*pdu) + (pdu->len = ntohs(pdu->len)) == len) {
 		switch (pdu->pid) {
 		case SDP_PDU_SERVICE_SEARCH_REQUEST:
 			error = server_prepare_service_search_response(srv, fd);
@@ -551,13 +500,13 @@ server_process_request(server_p srv, int32_t fd)
 		if (error != 0)
 			log_err("Could not send SDP response to %s socket, " \
 				"pdu->pid=%d, pdu->tid=%d, error=%d",
-				srv->fdidx[fd].control? "control" : "L2CAP",
+				srv->fdidx[fd].control? "control" : "L2CAP", 
 				pdu->pid, ntohs(pdu->tid), error);
 	} else {
 		log_err("Could not process SDP request from %s socket, " \
 			"pdu->pid=%d, pdu->tid=%d, pdu->len=%d, len=%d, " \
 			"error=%d",
-			srv->fdidx[fd].control? "control" : "L2CAP",
+			srv->fdidx[fd].control? "control" : "L2CAP", 
 			pdu->pid, ntohs(pdu->tid), pdu->len, len, error);
 
 		error = server_send_error_response(srv, fd, error);
@@ -568,7 +517,7 @@ server_process_request(server_p srv, int32_t fd)
 				pdu->pid, ntohs(pdu->tid), error);
 	}
 
-	/* On error forget response (if any) */
+	/* On error forget response (if any) */ 
 	if (error != 0) {
 		srv->fdidx[fd].rsp_cs = 0;
 		srv->fdidx[fd].rsp_size = 0;
@@ -638,39 +587,3 @@ server_close_fd(server_p srv, int32_t fd)
 	}
 }
 
-#if 0 /* XXX */
-static int
-/*server_auth_check(server_p srv, struct sockcred *cred)*/
-server_auth_check(server_p srv, struct cmsgcred *cred)
-{
-	struct group *grp;
-	int n;
-
-	if (cred == NULL)
-		return 0;
-
-	if (cred->cmcred_uid == 0 || cred->cmcred_euid == 0)
-		return 1;
-
-	if (srv->sgroup == NULL)
-		return 0;
-
-	grp = getgrnam(srv->sgroup);
-	if (grp == NULL) {
-		log_err("No gid for group '%s'", srv->sgroup);
-		srv->sgroup = NULL;
-		return 0;
-	}
-
-
-	if (cred->cmcred_gid == grp->gr_gid)
-		return 1;
-
-	for (n = 0 ; n < cred->cmcred_ngroups ; n++) {
-		if (cred->cmcred_groups[n] == grp->gr_gid)
-			return 1;
-	}
-
-	return 0;
-}
-#endif
diff --git a/usr.sbin/sdpd/server.h b/usr.sbin/sdpd/server.h
index 74411d18c0..50954eec65 100644
--- a/usr.sbin/sdpd/server.h
+++ b/usr.sbin/sdpd/server.h
@@ -1,34 +1,3 @@
-/* $NetBSD: server.h,v 1.3 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/server.h,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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. The name of Itronix Inc. may not be used to endorse
- *    or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
 /*
  * server.h
  *
@@ -56,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: server.h,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/server.h,v 1.2 2005/12/06 17:56:36 emax Exp $
+ * $Id: server.h,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/server.h 153176 2005-12-06 17:56:36Z emax $
  */
 
 #ifndef _SERVER_H_
@@ -90,13 +59,12 @@ typedef struct fd_idx *	fd_idx_p;
 
 struct server
 {
-	uint16_t		 imtu;		/* incoming MTU */
+	uint32_t		 imtu;		/* incoming MTU */
 	uint8_t			*req;		/* incoming buffer */
 	int32_t			 maxfd;		/* max. descriptor is the set */
 	fd_set			 fdset;		/* current descriptor set */
 	fd_idx_p		 fdidx;		/* descriptor index */
-	struct sockaddr_bt	 req_sa;	/* local address */
-	const char		*sgroup;	/* privileged group */
+	struct sockaddr_l2cap	 req_sa;	/* local address */
 };
 
 typedef struct server	server_t;
@@ -106,12 +74,10 @@ typedef struct server *	server_p;
  * External API
  */
 
-int32_t	server_init(server_p srv, const char *control, char const *sgroup);
+int32_t	server_init(server_p srv, const char *control);
 void	server_shutdown(server_p srv);
 int32_t	server_do(server_p srv);
 
-int	server_get_service_search_pattern(uint8_t const **buf, uint8_t const *end, uint128_t *uuid);
-
 int32_t	server_prepare_service_search_response(server_p srv, int32_t fd);
 int32_t	server_send_service_search_response(server_p srv, int32_t fd);
 
diff --git a/usr.sbin/sdpd/sp.c b/usr.sbin/sdpd/sp.c
index 936988be01..b3eeb8c8b4 100644
--- a/usr.sbin/sdpd/sp.c
+++ b/usr.sbin/sdpd/sp.c
@@ -1,6 +1,3 @@
-/* $NetBSD: sp.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/sp.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * sp.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: sp.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/sp.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ * $Id: sp.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/sp.c 124758 2004-01-20 20:48:26Z emax $
  */
 
 #include <sys/queue.h>
@@ -45,7 +42,7 @@ sp_profile_create_service_class_id_list(
 		uint8_t const *data, uint32_t datalen)
 {
 	static uint16_t	service_classes[] = {
-		SDP_SERVICE_CLASS_SERIAL_PORT
+		SDP_SERVICE_CLASS_SERIAL_PORT	
 	};
 
 	return (common_profile_create_service_class_id_list(
@@ -87,12 +84,12 @@ sp_profile_create_protocol_descriptor_list(
 		uint8_t *buf, uint8_t const * const eob,
 		uint8_t const *data, uint32_t datalen)
 {
-	provider_t const	*provider = (provider_t const *) data;
+	provider_p		provider = (provider_p) data;
 	sdp_sp_profile_p	sp = (sdp_sp_profile_p) provider->data;
 
 	return (rfcomm_profile_create_protocol_descriptor_list(
 			buf, eob,
-			(uint8_t const *) &sp->server_channel, 1));
+			(uint8_t const *) &sp->server_channel, 1)); 
 }
 
 static attr_t	sp_profile_attrs[] = {
@@ -111,16 +108,10 @@ static attr_t	sp_profile_attrs[] = {
 	{ 0, NULL } /* end entry */
 };
 
-static uint16_t sp_profile_uuids[] = {
-	SDP_SERVICE_CLASS_SERIAL_PORT,
-	SDP_UUID_PROTOCOL_L2CAP,
-	SDP_UUID_PROTOCOL_RFCOMM,
-};
-
 profile_t	sp_profile_descriptor = {
-	sp_profile_uuids,
-	sizeof(sp_profile_uuids),
+	SDP_SERVICE_CLASS_SERIAL_PORT,
 	sizeof(sdp_sp_profile_t),
 	common_profile_server_channel_valid,
 	(attr_t const * const) &sp_profile_attrs
 };
+
diff --git a/usr.sbin/sdpd/srr.c b/usr.sbin/sdpd/srr.c
index cc16564493..84d8c9c097 100644
--- a/usr.sbin/sdpd/srr.c
+++ b/usr.sbin/sdpd/srr.c
@@ -1,6 +1,3 @@
-/* $NetBSD: srr.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/srr.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * srr.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: srr.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/srr.c,v 1.2 2005/12/06 17:56:36 emax Exp $
+ * $Id: srr.c,v 1.1 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/srr.c 153176 2005-12-06 17:56:36Z emax $
  */
 
 #include <sys/queue.h>
@@ -58,7 +55,7 @@ server_prepare_service_register_response(server_p srv, int32_t fd)
 
 	profile_t	*profile = NULL;
 	provider_t	*provider = NULL;
-	bdaddr_t const	*bdaddr = NULL;
+	bdaddr_t	*bdaddr = NULL;
 	int32_t		 uuid;
 
 	/*
@@ -76,7 +73,7 @@ server_prepare_service_register_response(server_p srv, int32_t fd)
 	SDP_GET16(uuid, req);
 
 	/* Get BD_ADDR */
-	bdaddr = (bdaddr_t const *) req;
+	bdaddr = (bdaddr_p) req;
 	req += sizeof(*bdaddr);
 
 	/* Lookup profile descriptror */
@@ -97,7 +94,7 @@ server_prepare_service_register_response(server_p srv, int32_t fd)
 
 	SDP_PUT16(0, rsp);
 	SDP_PUT32(provider->handle, rsp);
-
+	
 	/* Set reply size */
 	srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t);
 	srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
@@ -139,3 +136,4 @@ server_send_service_register_response(server_p srv, int32_t fd)
 
 	return ((size < 0)? errno : 0);
 }
+
diff --git a/usr.sbin/sdpd/ssar.c b/usr.sbin/sdpd/ssar.c
index 443f23a65a..3bc17d0ef1 100644
--- a/usr.sbin/sdpd/ssar.c
+++ b/usr.sbin/sdpd/ssar.c
@@ -1,6 +1,3 @@
-/* $NetBSD: ssar.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/ssar.c,v 1.2 2008/05/19 10:19:49 corecode Exp $ */
-
 /*
  * ssar.c
  *
@@ -28,12 +25,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: ssar.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/ssar.c,v 1.2 2005/01/05 18:37:37 emax Exp $
+ * $Id: ssar.c,v 1.4 2004/01/12 22:54:31 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/ssar.c 139721 2005-01-05 18:37:37Z emax $
  */
 
 #include <sys/queue.h>
-#include <sys/select.h>
 #include <bluetooth.h>
 #include <sdp.h>
 #include <string.h>
@@ -42,6 +38,11 @@
 #include "server.h"
 #include "uuid-private.h"
 
+/* from sar.c */
+int32_t server_prepare_attr_list(provider_p const provider,
+		uint8_t const *req, uint8_t const * const req_end,
+		uint8_t *rsp, uint8_t const * const rsp_end);
+
 /*
  * Prepare SDP Service Search Attribute Response
  */
@@ -52,13 +53,14 @@ server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
 	uint8_t const	*req = srv->req + sizeof(sdp_pdu_t);
 	uint8_t const	*req_end = req + ((sdp_pdu_p)(srv->req))->len;
 	uint8_t		*rsp = srv->fdidx[fd].rsp;
-	uint8_t const	*rsp_end = rsp + L2CAP_MTU_MAXIMUM;
+	uint8_t const	*rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
 
-	uint8_t const	*aidptr = NULL;
+	uint8_t const	*sspptr = NULL, *aidptr = NULL;
+	uint8_t		*ptr = NULL;
 
 	provider_t	*provider = NULL;
-	int32_t		 type, rsp_limit, ucount, aidlen, cslen, cs;
-	uint128_t	 ulist[12];
+	int32_t		 type, rsp_limit, ssplen, aidlen, cslen, cs;
+	uint128_t	 uuid, puuid;
 
 	/*
 	 * Minimal Service Search Attribute Request request
@@ -71,11 +73,31 @@ server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
 	 * value8		- 1 byte  ContinuationState
 	 */
 
-	/* Get ServiceSearchPattern */
-	ucount = server_get_service_search_pattern(&req, req_end, ulist);
-	if (ucount < 1 || ucount > 12)
+	if (req_end - req < 13)
 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
 
+	/* Get size of ServiceSearchPattern */
+	ssplen = 0;
+	SDP_GET8(type, req);
+	switch (type) {
+	case SDP_DATA_SEQ8:
+		SDP_GET8(ssplen, req);
+		break;
+
+	case SDP_DATA_SEQ16:
+		SDP_GET16(ssplen, req);
+		break;
+
+	case SDP_DATA_SEQ32:
+		SDP_GET32(ssplen, req);
+		break;
+	}
+	if (ssplen <= 0)
+		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+	sspptr = req;
+	req += ssplen;
+
 	/* Get MaximumAttributeByteCount */
 	if (req + 2 > req_end)
 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
@@ -123,12 +145,13 @@ server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
 
 	SDP_GET8(cslen, req);
-	if (cslen == 2 && req + 2 == req_end)
+	if (cslen != 0) {
+		if (cslen != 2 || req_end - req != 2)
+			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
 		SDP_GET16(cs, req);
-	else if (cslen == 0 && req == req_end)
+	} else
 		cs = 0;
-	else
-		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
 
 	/* Process the request. First, check continuation state */
 	if (srv->fdidx[fd].rsp_cs != cs)
@@ -145,23 +168,70 @@ server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
 	 *	[ attr list ]
 	 */
 
-	rsp += 3;	/* leave space for sequence header */
-
-	for (provider = provider_get_first();
-	     provider != NULL;
-	     provider = provider_get_next(provider)) {
-		if (!provider_match_bdaddr(provider, &srv->req_sa.bt_bdaddr))
-			continue;
-
-		if (!provider_match_uuid(provider, ulist, ucount))
-			continue;
-
-		cs = server_prepare_attr_list(provider,
-			aidptr, aidptr + aidlen, rsp, rsp_end);
-		if (cs < 0)
-			return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
-
-		rsp += cs;
+	ptr = rsp + 3;
+
+	while (ssplen > 0) {
+		SDP_GET8(type, sspptr);
+		ssplen --;
+
+		switch (type) {
+		case SDP_DATA_UUID16:
+			if (ssplen < 2)
+				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+			memcpy(&uuid, &uuid_base, sizeof(uuid));
+			uuid.b[2] = *sspptr ++;
+			uuid.b[3] = *sspptr ++;
+			ssplen -= 2;
+			break;
+
+		case SDP_DATA_UUID32:
+			if (ssplen < 4)
+				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+			memcpy(&uuid, &uuid_base, sizeof(uuid));
+			uuid.b[0] = *sspptr ++;
+			uuid.b[1] = *sspptr ++;
+			uuid.b[2] = *sspptr ++;
+			uuid.b[3] = *sspptr ++;
+			ssplen -= 4;
+			break;
+
+		case SDP_DATA_UUID128:
+			if (ssplen < 16)
+				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+			memcpy(uuid.b, sspptr, 16);
+			sspptr += 16;	
+			ssplen -= 16; 
+			break;
+
+		default:
+			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+			/* NOT REACHED */
+		}
+
+		for (provider = provider_get_first();
+		     provider != NULL;
+		     provider = provider_get_next(provider)) {
+			if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
+				continue;
+
+			memcpy(&puuid, &uuid_base, sizeof(puuid));
+			puuid.b[2] = provider->profile->uuid >> 8;
+			puuid.b[3] = provider->profile->uuid;
+
+			if (memcmp(&uuid, &puuid, sizeof(uuid)) != 0 &&
+			    memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) != 0)
+				continue;
+
+			cs = server_prepare_attr_list(provider,
+				aidptr, aidptr + aidlen, ptr, rsp_end);
+			if (cs < 0)
+				return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
+
+			ptr += cs;
+		}
 	}
 
 	/* Set reply size (not counting PDU header and continuation state) */
@@ -169,13 +239,14 @@ server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
 	if (srv->fdidx[fd].rsp_limit > rsp_limit)
 		srv->fdidx[fd].rsp_limit = rsp_limit;
 
-	srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
+	srv->fdidx[fd].rsp_size = ptr - rsp;
 	srv->fdidx[fd].rsp_cs = 0;
 
 	/* Fix AttributeLists sequence header */
-	rsp = srv->fdidx[fd].rsp;
-	SDP_PUT8(SDP_DATA_SEQ16, rsp);
-	SDP_PUT16(srv->fdidx[fd].rsp_size - 3, rsp);
+	ptr = rsp;
+	SDP_PUT8(SDP_DATA_SEQ16, ptr);
+	SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr);
 
 	return (0);
 }
+
diff --git a/usr.sbin/sdpd/ssr.c b/usr.sbin/sdpd/ssr.c
index edde22a627..314cecbe24 100644
--- a/usr.sbin/sdpd/ssr.c
+++ b/usr.sbin/sdpd/ssr.c
@@ -1,6 +1,3 @@
-/* $NetBSD: ssr.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/ssr.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * ssr.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: ssr.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/ssr.c,v 1.3 2005/01/05 18:37:37 emax Exp $
+ * $Id: ssr.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/ssr.c 139721 2005-01-05 18:37:37Z emax $
  */
 
 #include <sys/queue.h>
@@ -46,104 +43,6 @@
 #include "server.h"
 #include "uuid-private.h"
 
-/*
- * Extract ServiceSearchPattern from request to uuid array
- *	return count or 0 if error
- */
-int
-server_get_service_search_pattern(uint8_t const **buf, uint8_t const *end, uint128_t *uuid)
-{
-	uint8_t const *req = *buf;
-	uint32_t type, ssplen;
-	int count;
-
-	if (req + 1 > end)
-		return 0;
-
-	SDP_GET8(type, req);
-
-	ssplen = 0;
-	switch (type) {
-	case SDP_DATA_SEQ8:
-		if (req + 1 > end)
-			return 0;
-
-		SDP_GET8(ssplen, req);
-		break;
-
-	case SDP_DATA_SEQ16:
-		if (req + 2 > end)
-			return 0;
-
-		SDP_GET16(ssplen, req);
-		break;
-
-	case SDP_DATA_SEQ32:
-		if (req + 4 > end)
-			return 0;
-
-		SDP_GET32(ssplen, req);
-		break;
-
-	default:
-		return 0;
-	}
-
-	if (req + ssplen > end)
-		return 0;
-
-	count = 0;
-	while (ssplen > 0) {
-		if (count == 12)
-			return 0;
-
-		SDP_GET8(type, req);
-		ssplen--;
-
-		switch (type) {
-		case SDP_DATA_UUID16:
-			if (ssplen < 2)
-				return 0;
-
-			memcpy(uuid, &uuid_base, sizeof(*uuid));
-			uuid->b[2] = *req++;
-			uuid->b[3] = *req++;
-			ssplen -= 2;
-			break;
-
-		case SDP_DATA_UUID32:
-			if (ssplen < 4)
-				return 0;
-
-			memcpy(uuid, &uuid_base, sizeof(*uuid));
-			uuid->b[0] = *req++;
-			uuid->b[1] = *req++;
-			uuid->b[2] = *req++;
-			uuid->b[3] = *req++;
-			ssplen -= 4;
-			break;
-
-		case SDP_DATA_UUID128:
-			if (ssplen < 16)
-				return 0;
-
-			memcpy(uuid, req, 16);
-			req += 16;
-			ssplen -= 16;
-			break;
-
-		default:
-			return 0;
-		}
-
-		count++;
-		uuid++;
-	}
-
-	*buf = req;
-	return count;
-}
-
 /*
  * Prepare SDP Service Search Response
  */
@@ -154,11 +53,12 @@ server_prepare_service_search_response(server_p srv, int32_t fd)
 	uint8_t const	*req = srv->req + sizeof(sdp_pdu_t);
 	uint8_t const	*req_end = req + ((sdp_pdu_p)(srv->req))->len;
 	uint8_t		*rsp = srv->fdidx[fd].rsp;
-	uint8_t const	*rsp_end = rsp + L2CAP_MTU_MAXIMUM;
+	uint8_t const	*rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
 
+	uint8_t		*ptr = NULL;
 	provider_t	*provider = NULL;
-	int32_t		 ucount, rsp_limit, cslen, cs;
-	uint128_t	 ulist[12];
+	int32_t		 type, ssplen, rsp_limit, rcount, cslen, cs;
+	uint128_t	 uuid, puuid;
 
 	/*
 	 * Minimal SDP Service Search Request
@@ -169,30 +69,50 @@ server_prepare_service_search_response(server_p srv, int32_t fd)
 	 * value8		- 1 byte  ContinuationState
 	 */
 
-	/* Get ServiceSearchPattern into uuid array */
-	ucount = server_get_service_search_pattern(&req, req_end, ulist);
-	if (ucount < 1 || ucount > 12)
+	if (req_end - req < 8)
 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
 
-	/* Get MaximumServiceRecordCount */
-	if (req + 2 > req_end)
+	/* Get size of ServiceSearchPattern */
+	ssplen = 0;
+	SDP_GET8(type, req);
+	switch (type) {
+	case SDP_DATA_SEQ8:
+		SDP_GET8(ssplen, req);
+		break;
+
+	case SDP_DATA_SEQ16:
+		SDP_GET16(ssplen, req);
+		break;
+
+	case SDP_DATA_SEQ32:
+		SDP_GET32(ssplen, req);
+		break;
+	}
+	if (ssplen <= 0)
 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
 
-	SDP_GET16(rsp_limit, req);
+	ptr = (uint8_t *) req + ssplen;
+
+	/* Get MaximumServiceRecordCount */
+	if (ptr + 2 > req_end)
+		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+	
+	SDP_GET16(rsp_limit, ptr);
 	if (rsp_limit <= 0)
 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
 
 	/* Get ContinuationState */
-	if (req + 1 > req_end)
+	if (ptr + 1 > req_end)
 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
 
-	SDP_GET8(cslen, req);
-	if (cslen == 2 && req + 2 == req_end)
-		SDP_GET16(cs, req);
-	else if (cslen == 0 && req == req_end)
+	SDP_GET8(cslen, ptr);
+	if (cslen != 0) {
+		if (cslen != 2 || req_end - ptr != 2)
+			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+		SDP_GET16(cs, ptr);
+	} else
 		cs = 0;
-	else
-		return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
 
 	/* Process the request. First, check continuation state */
 	if (srv->fdidx[fd].rsp_cs != cs)
@@ -207,27 +127,79 @@ server_prepare_service_search_response(server_p srv, int32_t fd)
 	 * value16	- 2 bytes CurrentServiceRecordCount (not incl.)
 	 * value32	- 4 bytes handle
 	 * [ value32 ]
+	 *
+	 * Calculate how many record handles we can fit 
+	 * in our reply buffer and adjust rlimit.
 	 */
 
-	/* Look for the record handles and add to the rsp buffer */
-	for (provider = provider_get_first();
-	     provider != NULL;
-	     provider = provider_get_next(provider)) {
-		if (!provider_match_bdaddr(provider, &srv->req_sa.bt_bdaddr))
-			continue;
+	ptr = rsp;
+	rcount = (rsp_end - ptr) / 4;
+	if (rcount < rsp_limit)
+		rsp_limit = rcount;
+
+	/* Look for the record handles */
+	for (rcount = 0; ssplen > 0 && rcount < rsp_limit; ) {
+		SDP_GET8(type, req);
+		ssplen --;
 
-		if (!provider_match_uuid(provider, ulist, ucount))
-			continue;
+		switch (type) {
+		case SDP_DATA_UUID16:
+			if (ssplen < 2)
+				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
 
-		if (rsp + 4 > rsp_end)
+			memcpy(&uuid, &uuid_base, sizeof(uuid));
+			uuid.b[2] = *req ++;
+			uuid.b[3] = *req ++;
+			ssplen -= 2;
 			break;
 
-		SDP_PUT32(provider->handle, rsp);
+		case SDP_DATA_UUID32:
+			if (ssplen < 4)
+				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+			memcpy(&uuid, &uuid_base, sizeof(uuid));
+			uuid.b[0] = *req ++;
+			uuid.b[1] = *req ++;
+			uuid.b[2] = *req ++;
+			uuid.b[3] = *req ++;
+			ssplen -= 4;
+			break;
+
+		case SDP_DATA_UUID128:
+			if (ssplen < 16)
+				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+			memcpy(uuid.b, req, 16);
+			req += 16;
+			ssplen -= 16; 
+			break;
+
+		default:
+			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+			/* NOT REACHED */
+		}
+
+		for (provider = provider_get_first();
+		     provider != NULL && rcount < rsp_limit;
+		     provider = provider_get_next(provider)) {
+			if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
+				continue;
+
+			memcpy(&puuid, &uuid_base, sizeof(puuid));
+			puuid.b[2] = provider->profile->uuid >> 8;
+			puuid.b[3] = provider->profile->uuid;
+
+			if (memcmp(&uuid, &puuid, sizeof(uuid)) == 0 ||
+			    memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) == 0) {
+				SDP_PUT32(provider->handle, ptr);
+				rcount ++;
+			}
+		}
 	}
 
 	/* Set reply size (not counting PDU header and continuation state) */
 	srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 4;
-	srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
+	srv->fdidx[fd].rsp_size = ptr - rsp;
 	srv->fdidx[fd].rsp_cs = 0;
 
 	return (0);
@@ -256,7 +228,7 @@ server_send_service_search_response(server_p srv, int32_t fd)
 	if (size + 1 > srv->fdidx[fd].rsp_limit) {
 		/*
 		 * We need to split out response. Add 3 more bytes for the
-		 * continuation state and move rsp_end and rsp_cs backwards.
+		 * continuation state and move rsp_end and rsp_cs backwards. 
 		 */
 
 		while ((rsp_end - rsp) + 3 > srv->fdidx[fd].rsp_limit) {
@@ -307,3 +279,4 @@ server_send_service_search_response(server_p srv, int32_t fd)
 
 	return ((size < 0)? errno : 0);
 }
+
diff --git a/usr.sbin/sdpd/sur.c b/usr.sbin/sdpd/sur.c
index 1d18660c6f..1cdd456f4a 100644
--- a/usr.sbin/sdpd/sur.c
+++ b/usr.sbin/sdpd/sur.c
@@ -1,6 +1,3 @@
-/* $NetBSD: sur.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/sur.c,v 1.2 2008/05/19 10:19:49 corecode Exp $ */
-
 /*
  * sur.c
  *
@@ -28,12 +25,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: sur.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/sur.c,v 1.2 2005/12/06 17:56:36 emax Exp $
+ * $Id: sur.c,v 1.1 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/sur.c 153176 2005-12-06 17:56:36Z emax $
  */
 
 #include <sys/queue.h>
-#include <sys/select.h>
 #include <bluetooth.h>
 #include <errno.h>
 #include <sdp.h>
@@ -84,3 +80,4 @@ server_prepare_service_unregister_response(server_p srv, int32_t fd)
 
 	return (0);
 }
+
diff --git a/usr.sbin/sdpd/uuid-private.h b/usr.sbin/sdpd/uuid-private.h
index ca0daf7634..2f6fbe15ee 100644
--- a/usr.sbin/sdpd/uuid-private.h
+++ b/usr.sbin/sdpd/uuid-private.h
@@ -1,6 +1,3 @@
-/* $NetBSD: uuid-private.h,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/uuid-private.h,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * uuid-private.h
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: uuid-private.h,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/uuid-private.h,v 1.1 2005/01/05 18:37:37 emax Exp $
+ * $Id: uuid-private.h,v 1.1 2004/12/09 18:20:26 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/uuid-private.h 139721 2005-01-05 18:37:37Z emax $
  */
 
 #ifndef _UUID_PRIVATE_H_
@@ -39,3 +36,4 @@ extern	uint128_t	uuid_base;
 extern	uint128_t	uuid_public_browse_group;
 
 #endif /* ndef _UUID_PRIVATE_H_ */
+
diff --git a/usr.sbin/sdpd/uuid.c b/usr.sbin/sdpd/uuid.c
index 4c80f2eda7..e1de5af7d1 100644
--- a/usr.sbin/sdpd/uuid.c
+++ b/usr.sbin/sdpd/uuid.c
@@ -1,6 +1,3 @@
-/* $NetBSD: uuid.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
-/* $DragonFly: src/usr.sbin/sdpd/uuid.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
-
 /*
  * uuid.c
  *
@@ -28,8 +25,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: uuid.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
- * $FreeBSD: src/usr.sbin/bluetooth/sdpd/uuid.c,v 1.1 2005/01/05 18:37:37 emax Exp $
+ * $Id: uuid.c,v 1.1 2004/12/09 18:20:26 max Exp $
+ * $FreeBSD: head/usr.sbin/bluetooth/sdpd/uuid.c 139721 2005-01-05 18:37:37Z emax $
  */
 
 #include <bluetooth.h>
@@ -56,3 +53,4 @@ uint128_t	uuid_public_browse_group = {
 		0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
 	}
 };
+
-- 
2.26.1

