func (c *Conn) Close() error {
	select {
	case <-c.chDone:
		return nil
	default:
		err := c.hci.Send(&cmd.Disconnect{
			ConnectionHandle: c.param.ConnectionHandle(),
			Reason:           0x13,
		}, nil)
		c.Debugf("conn connection close called")
		_ = c.hci.cleanupConnectionHandle(c.param.ConnectionHandle())
		return err
	}
}
Close disconnects the connection by sending hci disconnect command to the device.
package hci
import (
	"bytes"
	"context"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"time"
	"github.com/pkg/errors"
	"github.com/rigado/ble"
	"github.com/rigado/ble/linux/hci/cmd"
	"github.com/rigado/ble/linux/hci/evt"
)
type Conn struct {
	hci *HCI
	ctx context.Context
	param evt.LEConnectionComplete
	rxMTU int
	txMTU int
	rxMPS int
	sigRxMTU int
	sigTxMTU int
	sigSent chan []byte
	chInPkt chan packet
	chInPDU chan pdu
	chDone chan struct{}
	txBuffer *Client
	sigID uint8
	leFrame bool
	smp        SmpManager
	encChanged chan ble.EncryptionChangedInfo
	ble.Logger
}
type Encrypter interface {
	Encrypt() error
}
func newConn(h *HCI, param evt.LEConnectionComplete, mac string) *Conn {
	c := &Conn{
		hci:   h,
		ctx:   context.Background(),
		param: param,
		rxMTU: ble.DefaultMTU,
		txMTU: ble.DefaultMTU,
		rxMPS: ble.DefaultMTU,
		sigRxMTU: ble.MaxMTU,
		sigTxMTU: ble.DefaultMTU,
		chInPkt: make(chan packet, 16),
		chInPDU: make(chan pdu, 16),
		txBuffer: NewClient(h.pool),
		chDone: make(chan struct{}),
		Logger: h.Logger.ChildLogger(map[string]interface{}{"l2cap": mac}),
	}
	if c.hci.smpEnabled {
		c.smp = c.hci.smp.Create(defaultSmpConfig, c.Logger)
		c.initPairingContext()
		c.smp.SetWritePDUFunc(c.writePDU)
		c.smp.SetEncryptFunc(c.encrypt)
	}
	go func() {
		for {
			if err := c.recombine(); err != nil {
				if err != io.EOF {
					err = errors.Wrap(err, "recombine")
					c.hci.dispatchError(err)
					c.Errorf("recombineLoop: %v, cleaning up connection handle", err)
					if err := c.hci.cleanupConnectionHandle(c.param.ConnectionHandle()); err != nil {
						c.Errorf("recombineLoop: cleanup %v", err)
					}
				}
				close(c.chInPDU)
				return
			}
		}
	}()
	return c
}
func (c *Conn) Context() context.Context {
	return c.ctx
}
func (c *Conn) SetContext(ctx context.Context) {
	c.ctx = ctx
}
func (c *Conn) Pair(authData ble.AuthData, to time.Duration) error {
	return c.smp.Pair(authData, to)
}
func (c *Conn) StartEncryption(ch chan ble.EncryptionChangedInfo) error {
	c.encChanged = ch
	err := c.smp.StartEncryption()
	if err != nil {
		c.encChanged = nil
	}
	return err
}
func (c *Conn) Read(sdu []byte) (n int, err error) {
	p, ok := <-c.chInPDU
	if !ok {
		return 0, errors.Wrap(io.ErrClosedPipe, "input channel closed")
	}
	if len(p) == 0 {
		return 0, errors.Wrap(io.ErrUnexpectedEOF, "received empty packet")
	}
	slen := p.dlen()
	data := p.payload()
	if c.leFrame {
		slen = leFrameHdr(p).slen()
		data = leFrameHdr(p).payload()
	}
	if cap(sdu) < slen {
		return 0, errors.Wrapf(io.ErrShortBuffer, "payload received exceeds sdu buffer")
	}
	buf := bytes.NewBuffer(sdu)
	buf.Reset()
	buf.Write(data)
	for buf.Len() < slen {
		p := <-c.chInPDU
		buf.Write(p.payload())
	}
	return slen, nil
}
func (c *Conn) Write(sdu []byte) (int, error) {
	if len(sdu) > c.txMTU {
		return 0, errors.Wrap(io.ErrShortWrite, "payload exceeds mtu")
	}
	plen := len(sdu)
	if plen > c.txMTU {
		plen = c.txMTU
	}
	b := make([]byte, 4+plen)
	binary.LittleEndian.PutUint16(b[0:2], uint16(len(sdu)))
	binary.LittleEndian.PutUint16(b[2:4], cidLEAtt)
	if c.leFrame {
		binary.LittleEndian.PutUint16(b[4:6], uint16(len(sdu)))
		copy(b[6:], sdu)
	} else {
		copy(b[4:], sdu)
	}
	sent, err := c.writePDU(b)
	if err != nil {
		return sent, err
	}
	sdu = sdu[plen:]
	for len(sdu) > 0 {
		plen := len(sdu)
		if plen > c.txMTU {
			plen = c.txMTU
		}
		n, err := c.writePDU(sdu[:plen])
		sent += n
		if err != nil {
			return sent, err
		}
		sdu = sdu[plen:]
	}
	return sent, nil
}
func (c *Conn) initPairingContext() {
	smp := c.smp
	la := c.LocalAddr().Bytes()
	lat := uint8(0x00)
	if (la[0] & 0xc0) == 0xc0 {
		lat = 0x01
	}
	ra := c.RemoteAddr().Bytes()
	rat := c.param.PeerAddressType()
	smp.InitContext(la, ra, lat, rat)
}
func (c *Conn) encrypt(bi BondInfo) error {
	legacy, stk := c.smp.LegacyPairingInfo()
	if legacy && len(stk) > 0 {
		c.Infof("encrypt: using short term key")
		return c.stkEncrypt(stk)
	}
	if bi == nil {
		return fmt.Errorf("no bond information")
	}
	ltk := bi.LongTermKey()
	if ltk == nil {
		return fmt.Errorf("no ltk present")
	}
	m := cmd.LEStartEncryption{}
	m.ConnectionHandle = c.param.ConnectionHandle()
	eDiv := bi.EDiv()
	randVal := bi.Random()
	if bi.Legacy() {
		if len(ltk) != 16 {
			return fmt.Errorf("invalid length for ltk")
		}
		if eDiv == 0 || randVal == 0 {
			return fmt.Errorf("ediv and random must not be 0 for legacy pairing")
		}
	}
	for i, v := range ltk {
		m.LongTermKey[i] = v
	}
	m.EncryptedDiversifier = eDiv
	m.RandomNumber = randVal
	return c.hci.Send(&m, nil)
}
func (c *Conn) stkEncrypt(key []byte) error {
	m := cmd.LEStartEncryption{}
	m.ConnectionHandle = c.param.ConnectionHandle()
	for i, v := range key {
		m.LongTermKey[i] = v
	}
	m.EncryptedDiversifier = 0
	m.RandomNumber = 0
	return c.hci.Send(&m, nil)
}
func (c *Conn) writePDU(pdu []byte) (int, error) {
	sent := 0
	flags := uint16(pbfHostToControllerStart << 4)  
	c.txBuffer.LockPool()
	defer c.txBuffer.UnlockPool()
	select {
	case <-c.chDone:
		return 0, io.ErrClosedPipe
	default:
	}
	for len(pdu) > 0 {
		pkt := c.txBuffer.Get()  
		flen := len(pdu)         
		if flen > pkt.Cap()-1-4 {
			flen = pkt.Cap() - 1 - 4
		}
		if err := binary.Write(pkt, binary.LittleEndian, pktTypeACLData); err != nil {
			return 0, err
		}
		if err := binary.Write(pkt, binary.LittleEndian, c.param.ConnectionHandle()|(flags<<8)); err != nil {
			return 0, err
		}
		if err := binary.Write(pkt, binary.LittleEndian, uint16(flen)); err != nil {
			return 0, err
		}
		if err := binary.Write(pkt, binary.LittleEndian, pdu[:flen]); err != nil {
			return 0, err
		}
		select {
		case <-c.chDone:
			return 0, io.ErrClosedPipe
		default:
		}
		if _, err := c.hci.skt.Write(pkt.Bytes()); err != nil {
			return sent, err
		}
		sent += flen
		flags = (pbfContinuing << 4)  
		pdu = pdu[flen:]              
	}
	return sent, nil
}
func (c *Conn) recombine() error {
	var pkt packet
	var ok bool
	select {
	case <-c.hci.done:
		return io.EOF
	case pkt, ok = <-c.chInPkt:
		if !ok {
			return io.EOF
		}
	}
	p := pdu(pkt.data())
	c.Debugf("recombine: pdu in - % X", pkt.data())
	if p.cid() == cidLEAtt && p.dlen() > c.rxMPS {
		return fmt.Errorf("fragment size (%d) larger than rxMPS (%d)", p.dlen(), c.rxMPS)
	}
	if len(p.payload()) < p.dlen() {
		p = make([]byte, 0, 4+p.dlen())
		p = append(p, pdu(pkt.data())...)
	}
	for len(p) < 4+p.dlen() {
		select {
		case <-c.hci.done:
			return io.EOF
		case pkt, ok = <-c.chInPkt:
			if !ok || (pkt.pbf()&pbfContinuing) == 0 {
				return io.ErrUnexpectedEOF
			}
		}
		p = append(p, pdu(pkt.data())...)
	}
	switch p.cid() {
	case cidLEAtt:
		c.chInPDU <- p
	case cidLESignal:
		_ = c.handleSignal(p)
	case CidSMP:
		if c.smp == nil {
			c.Errorf("recombine: smp nil")
		} else if err := c.smp.Handle(p); err != nil {
			c.Errorf("recombine: smp.Handle - %v", err)
		}
	default:
		c.Errorf("recombine: unrecognized CID %04X, [%X]", p.cid(), p)
	}
	return nil
}
func (c *Conn) handleEncryptionChanged(status uint8, enabled uint8) {
	var err error
	if status != 0x00 {
		cmdErr := ErrCommand(status)
		err = fmt.Errorf(errCmd[cmdErr])
		if de := c.smp.DeleteBondInfo(); de != nil {
			c.Errorf("encryptionChanged: failed to delete bond info: %v", err)
		}
	}
	info := ble.EncryptionChangedInfo{Status: int(status), Err: err, Enabled: enabled == 0x01}
	if c.encChanged != nil {
		select {
		case c.encChanged <- info:
			return
		default:
			c.Errorf("encryptionChanged: failed to send encryption changed status to channel: %v", info)
		}
	} else {
		c.Infof("encryptionChanged: status %v, err %v", status, err)
	}
}
func (c *Conn) Disconnected() <-chan struct{} {
	return c.chDone
}