You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2017/08/07 20:14:26 UTC

[mynewt-newtmgr] 04/06: nmxact - more consolidation of plain/omp sesn.

This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newtmgr.git

commit cb77576fdc1f9f9761f14a2cafdb8e7d19139281
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Fri Aug 4 18:29:56 2017 -0700

    nmxact - more consolidation of plain/omp sesn.
---
 newtmgr/bll/bll_common.go                    |   6 +-
 newtmgr/bll/bll_plain_sesn.go                | 291 ---------------------------
 newtmgr/bll/{bll_oic_sesn.go => bll_sesn.go} | 264 +++++++++++-------------
 newtmgr/bll/bll_sesn_cfg.go                  |   2 +-
 newtmgr/bll/bll_xport.go                     |  11 +-
 nmxact/nmble/ble_sesn.go                     |  45 ++---
 nmxact/nmble/ble_util.go                     |  53 +++++
 nmxact/nmble/conn.go                         |   8 +-
 8 files changed, 195 insertions(+), 485 deletions(-)

diff --git a/newtmgr/bll/bll_common.go b/newtmgr/bll/bll_common.go
index 93efd06..59a49f2 100644
--- a/newtmgr/bll/bll_common.go
+++ b/newtmgr/bll/bll_common.go
@@ -31,7 +31,7 @@ import (
 	"mynewt.apache.org/newtmgr/nmxact/bledefs"
 )
 
-func exchangeMtu(cln ble.Client, preferredMtu int) (int, error) {
+func exchangeMtu(cln ble.Client, preferredMtu uint16) (uint16, error) {
 	log.Debugf("Exchanging MTU")
 
 	// We loop three times here to workaround an library issue with macOS.  In
@@ -43,7 +43,7 @@ func exchangeMtu(cln ble.Client, preferredMtu int) (int, error) {
 	var mtu int
 	for i := 0; i < 3; i++ {
 		var err error
-		mtu, err = cln.ExchangeMTU(preferredMtu)
+		mtu, err = cln.ExchangeMTU(int(preferredMtu))
 		if err != nil {
 			return 0, err
 		}
@@ -66,5 +66,5 @@ func exchangeMtu(cln ble.Client, preferredMtu int) (int, error) {
 	}
 
 	log.Debugf("Exchanged MTU; ATT MTU = %d", mtu)
-	return mtu, nil
+	return uint16(mtu), nil
 }
diff --git a/newtmgr/bll/bll_plain_sesn.go b/newtmgr/bll/bll_plain_sesn.go
deleted file mode 100644
index 14ef250..0000000
--- a/newtmgr/bll/bll_plain_sesn.go
+++ /dev/null
@@ -1,291 +0,0 @@
-// +build !windows
-
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package bll
-
-import (
-	"fmt"
-
-	log "github.com/Sirupsen/logrus"
-	"github.com/currantlabs/ble"
-	"github.com/runtimeco/go-coap"
-	"golang.org/x/net/context"
-
-	"mynewt.apache.org/newtmgr/newtmgr/nmutil"
-	"mynewt.apache.org/newtmgr/nmxact/bledefs"
-	"mynewt.apache.org/newtmgr/nmxact/nmble"
-	"mynewt.apache.org/newtmgr/nmxact/nmp"
-	"mynewt.apache.org/newtmgr/nmxact/nmxutil"
-	"mynewt.apache.org/newtmgr/nmxact/sesn"
-)
-
-type BllPlainSesn struct {
-	cfg BllSesnCfg
-
-	cln    ble.Client
-	nmpChr *ble.Characteristic
-	d      *nmp.Dispatcher
-	attMtu int
-}
-
-func NewBllPlainSesn(cfg BllSesnCfg) *BllPlainSesn {
-	return &BllPlainSesn{
-		cfg: cfg,
-		d:   nmp.NewDispatcher(1),
-	}
-}
-
-func (bps *BllPlainSesn) listenDisconnect() {
-	go func() {
-		<-bps.cln.Disconnected()
-
-		bps.d.ErrorAll(fmt.Errorf("Disconnected"))
-		bps.cln = nil
-	}()
-}
-
-func (bps *BllPlainSesn) connect() error {
-	log.Debugf("Connecting to peer")
-	ctx := ble.WithSigHandler(context.WithTimeout(context.Background(),
-		bps.cfg.ConnTimeout))
-
-	var err error
-	bps.cln, err = ble.Connect(ctx, bps.cfg.AdvFilter)
-	if err != nil {
-		if nmutil.ErrorCausedBy(err, context.DeadlineExceeded) {
-			return fmt.Errorf("Failed to connect to peer after %s",
-				bps.cfg.ConnTimeout.String())
-		} else {
-			return err
-		}
-	}
-
-	bps.listenDisconnect()
-
-	return nil
-}
-
-func (bps *BllPlainSesn) discoverAll() error {
-	log.Debugf("Discovering profile")
-	p, err := bps.cln.DiscoverProfile(true)
-	if err != nil {
-		return err
-	}
-
-	svcUuid, _ := bledefs.ParseUuid(bledefs.NmpPlainSvcUuid)
-	chrUuid, _ := bledefs.ParseUuid(bledefs.NmpPlainChrUuid)
-
-	for _, s := range p.Services {
-		uuid, err := UuidFromBllUuid(s.UUID)
-		if err != nil {
-			return err
-		}
-
-		if bledefs.CompareUuids(uuid, svcUuid) == 0 {
-			for _, c := range s.Characteristics {
-				uuid, err := UuidFromBllUuid(c.UUID)
-				if err != nil {
-					return err
-				}
-
-				if bledefs.CompareUuids(uuid, chrUuid) == 0 {
-					bps.nmpChr = c
-					return nil
-				}
-			}
-		}
-	}
-
-	return fmt.Errorf(
-		"Peer doesn't support a suitable service / characteristic")
-}
-
-// Subscribes to the peer's characteristic implementing NMP.
-func (bps *BllPlainSesn) subscribe() error {
-	log.Debugf("Subscribing to NMP response characteristic")
-	onNotify := func(data []byte) {
-		bps.d.Dispatch(data)
-	}
-
-	if err := bps.cln.Subscribe(bps.nmpChr, false, onNotify); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func (bps *BllPlainSesn) exchangeMtu() error {
-	mtu, err := exchangeMtu(bps.cln, bps.cfg.PreferredMtu)
-	if err != nil {
-		return err
-	}
-
-	bps.attMtu = mtu
-	return nil
-}
-
-// @return bool                 Whether to retry the open attempt; false
-//                                  on success.
-//         error                The cause of a failed open; nil on success.
-func (bps *BllPlainSesn) openOnce() (bool, error) {
-	if bps.IsOpen() {
-		return false, nmxutil.NewSesnAlreadyOpenError(
-			"Attempt to open an already-open bll session")
-	}
-
-	if err := bps.connect(); err != nil {
-		return false, err
-	}
-
-	if err := bps.exchangeMtu(); err != nil {
-		return true, err
-	}
-
-	if err := bps.discoverAll(); err != nil {
-		return false, err
-	}
-
-	if err := bps.subscribe(); err != nil {
-		return false, err
-	}
-
-	return false, nil
-}
-
-func (bps *BllPlainSesn) Open() error {
-	var err error
-
-	for i := 0; i < bps.cfg.ConnTries; i++ {
-		var retry bool
-
-		retry, err = bps.openOnce()
-		if !retry {
-			break
-		}
-	}
-
-	if err != nil {
-		// Ensure the session is closed.
-		bps.Close()
-		return err
-	}
-
-	return nil
-}
-
-func (bps *BllPlainSesn) Close() error {
-	if !bps.IsOpen() {
-		return nmxutil.NewSesnClosedError(
-			"Attempt to close an unopened bll session")
-	}
-
-	if err := bps.cln.CancelConnection(); err != nil {
-		return err
-	}
-
-	bps.cln = nil
-
-	return nil
-}
-
-// Indicates whether the session is currently open.
-func (bps *BllPlainSesn) IsOpen() bool {
-	return bps.cln != nil
-}
-
-// Retrieves the maximum data payload for outgoing NMP requests.
-func (bps *BllPlainSesn) MtuOut() int {
-	return bps.attMtu - nmble.NOTIFY_CMD_BASE_SZ - nmp.NMP_HDR_SIZE
-}
-
-// Retrieves the maximum data payload for incoming NMP responses.
-func (bps *BllPlainSesn) MtuIn() int {
-	return bps.attMtu - nmble.NOTIFY_CMD_BASE_SZ - nmp.NMP_HDR_SIZE
-}
-
-// Stops a receive operation in progress.  This must be called from a
-// separate thread, as sesn receive operations are blocking.
-func (bps *BllPlainSesn) AbortRx(nmpSeq uint8) error {
-	return bps.d.ErrorOne(nmpSeq, fmt.Errorf("Rx aborted"))
-}
-
-func (bps *BllPlainSesn) EncodeNmpMsg(msg *nmp.NmpMsg) ([]byte, error) {
-	return nmp.EncodeNmpPlain(msg)
-}
-
-// Performs a blocking transmit a single NMP message and listens for the
-// response.
-//     * nil: success.
-//     * nmxutil.SesnClosedError: session not open.
-//     * other error
-func (bps *BllPlainSesn) TxNmpOnce(msg *nmp.NmpMsg, opt sesn.TxOptions) (
-	nmp.NmpRsp, error) {
-
-	if !bps.IsOpen() {
-		return nil, nmxutil.NewSesnClosedError(
-			"Attempt to transmit over closed BLE session")
-	}
-
-	b, err := bps.EncodeNmpMsg(msg)
-	if err != nil {
-		return nil, err
-	}
-
-	nl, err := bps.d.AddListener(msg.Hdr.Seq)
-	if err != nil {
-		return nil, err
-	}
-	defer bps.d.RemoveListener(msg.Hdr.Seq)
-
-	// Send request.
-	if err := bps.cln.WriteCharacteristic(bps.nmpChr, b, true); err != nil {
-		return nil, err
-	}
-
-	// Now wait for NMP response.
-	for {
-		select {
-		case err := <-nl.ErrChan:
-			return nil, err
-		case rsp := <-nl.RspChan:
-			return rsp, nil
-		case <-nl.AfterTimeout(opt.Timeout):
-			msg := fmt.Sprintf(
-				"NMP timeout; op=%d group=%d id=%d seq=%d",
-				b[0], b[4]+b[5]<<8, b[7], b[6])
-
-			return nil, nmxutil.NewRspTimeoutError(msg)
-		}
-	}
-}
-
-func (bps *BllPlainSesn) GetResourceOnce(resType sesn.ResourceType, uri string,
-	opt sesn.TxOptions) (coap.COAPCode, []byte, error) {
-
-	return 0, nil,
-		fmt.Errorf("Resource API not supported by plain (non-OIC) session")
-}
-
-func (bps *BllPlainSesn) PutResourceOnce(resType sesn.ResourceType,
-	uri string, value []byte, opt sesn.TxOptions) (coap.COAPCode, error) {
-
-	return 0, fmt.Errorf("BllPlainSesn.PutResourceOnce() unsupported")
-}
diff --git a/newtmgr/bll/bll_oic_sesn.go b/newtmgr/bll/bll_sesn.go
similarity index 54%
rename from newtmgr/bll/bll_oic_sesn.go
rename to newtmgr/bll/bll_sesn.go
index e813967..0e272dd 100644
--- a/newtmgr/bll/bll_oic_sesn.go
+++ b/newtmgr/bll/bll_sesn.go
@@ -32,21 +32,21 @@ import (
 
 	"mynewt.apache.org/newtmgr/newtmgr/nmutil"
 	"mynewt.apache.org/newtmgr/nmxact/bledefs"
+	"mynewt.apache.org/newtmgr/nmxact/mgmt"
 	"mynewt.apache.org/newtmgr/nmxact/nmble"
 	"mynewt.apache.org/newtmgr/nmxact/nmp"
 	"mynewt.apache.org/newtmgr/nmxact/nmxutil"
 	"mynewt.apache.org/newtmgr/nmxact/oic"
-	"mynewt.apache.org/newtmgr/nmxact/omp"
 	"mynewt.apache.org/newtmgr/nmxact/sesn"
 )
 
-type BllOicSesn struct {
+type BllSesn struct {
 	cfg BllSesnCfg
 
 	cln    ble.Client
-	d      *omp.Dispatcher
+	txvr   *mgmt.Transceiver
 	mtx    sync.Mutex
-	attMtu int
+	attMtu uint16
 
 	nmpReqChr    *ble.Characteristic
 	nmpRspChr    *ble.Characteristic
@@ -58,42 +58,41 @@ type BllOicSesn struct {
 	secureRspChr *ble.Characteristic
 }
 
-func NewBllOicSesn(cfg BllSesnCfg) *BllOicSesn {
-	return &BllOicSesn{
+func NewBllSesn(cfg BllSesnCfg) *BllSesn {
+	return &BllSesn{
 		cfg: cfg,
 	}
 }
 
-func (bls *BllOicSesn) listenDisconnect() {
+func (s *BllSesn) listenDisconnect() {
 	go func() {
-		<-bls.cln.Disconnected()
+		<-s.cln.Disconnected()
 
-		bls.mtx.Lock()
-		bls.d.ErrorAll(fmt.Errorf("Disconnected"))
-		bls.d.Stop()
-		bls.mtx.Unlock()
+		s.mtx.Lock()
+		s.txvr.ErrorAll(fmt.Errorf("disconnected"))
+		s.mtx.Unlock()
 
-		bls.cln = nil
+		s.cln = nil
 	}()
 }
 
-func (bls *BllOicSesn) connect() error {
+func (s *BllSesn) connect() error {
 	log.Debugf("Connecting to peer")
 	ctx := ble.WithSigHandler(context.WithTimeout(context.Background(),
-		bls.cfg.ConnTimeout))
+		s.cfg.ConnTimeout))
 
 	var err error
-	bls.cln, err = ble.Connect(ctx, bls.cfg.AdvFilter)
+	s.cln, err = ble.Connect(ctx, s.cfg.AdvFilter)
 	if err != nil {
 		if nmutil.ErrorCausedBy(err, context.DeadlineExceeded) {
 			return fmt.Errorf("Failed to connect to peer after %s",
-				bls.cfg.ConnTimeout.String())
+				s.cfg.ConnTimeout.String())
 		} else {
 			return err
 		}
 	}
 
-	bls.listenDisconnect()
+	s.listenDisconnect()
 
 	return nil
 }
@@ -124,13 +123,16 @@ func findChr(profile *ble.Profile, svcUuid bledefs.BleUuid,
 	return nil, nil
 }
 
-func (bls *BllOicSesn) discoverAll() error {
+func (s *BllSesn) discoverAll() error {
 	log.Debugf("Discovering profile")
-	p, err := bls.cln.DiscoverProfile(true)
+	p, err := s.cln.DiscoverProfile(true)
 	if err != nil {
 		return err
 	}
 
+	nmpSvcUuid, _ := bledefs.ParseUuid(bledefs.NmpPlainSvcUuid)
+	nmpChrUuid, _ := bledefs.ParseUuid(bledefs.NmpPlainChrUuid)
+
 	ompSvcUuid, _ := bledefs.ParseUuid(bledefs.OmpUnsecSvcUuid)
 	ompReqChrUuid, _ := bledefs.ParseUuid(bledefs.OmpUnsecReqChrUuid)
 	ompRspChrUuid, _ := bledefs.ParseUuid(bledefs.OmpUnsecRspChrUuid)
@@ -139,22 +141,35 @@ func (bls *BllOicSesn) discoverAll() error {
 	unauthReqChrUuid, _ := bledefs.ParseUuid(bledefs.UnauthReqChrUuid)
 	unauthRspChrUuid, _ := bledefs.ParseUuid(bledefs.UnauthRspChrUuid)
 
-	bls.nmpReqChr, err = findChr(p, ompSvcUuid, ompReqChrUuid)
-	if err != nil {
-		return err
-	}
+	switch s.cfg.MgmtProto {
+	case sesn.MGMT_PROTO_NMP:
+		s.nmpReqChr, err = findChr(p, nmpSvcUuid, nmpChrUuid)
+		if err != nil {
+			return err
+		}
+		s.nmpRspChr = s.nmpReqChr
 
-	bls.nmpRspChr, err = findChr(p, ompSvcUuid, ompRspChrUuid)
-	if err != nil {
-		return err
+	case sesn.MGMT_PROTO_OMP:
+		s.nmpReqChr, err = findChr(p, ompSvcUuid, ompReqChrUuid)
+		if err != nil {
+			return err
+		}
+
+		s.nmpRspChr, err = findChr(p, ompSvcUuid, ompRspChrUuid)
+		if err != nil {
+			return err
+		}
+
+	default:
+		return fmt.Errorf("invalid management protocol: %s", s.cfg.MgmtProto)
 	}
 
-	bls.unauthReqChr, err = findChr(p, unauthSvcUuid, unauthReqChrUuid)
+	s.unauthReqChr, err = findChr(p, unauthSvcUuid, unauthReqChrUuid)
 	if err != nil {
 		return err
 	}
 
-	bls.unauthRspChr, err = findChr(p, unauthSvcUuid, unauthRspChrUuid)
+	s.unauthRspChr, err = findChr(p, unauthSvcUuid, unauthRspChrUuid)
 	if err != nil {
 		return err
 	}
@@ -163,22 +178,22 @@ func (bls *BllOicSesn) discoverAll() error {
 }
 
 // Subscribes to the peer's characteristic implementing NMP.
-func (bls *BllOicSesn) subscribe() error {
+func (s *BllSesn) subscribe() error {
 	log.Debugf("Subscribing to NMP response characteristic")
 	onNotify := func(data []byte) {
-		bls.d.Dispatch(data)
+		s.txvr.DispatchNmpRsp(data)
 	}
 
-	if bls.nmpRspChr != nil {
-		if err := bls.cln.Subscribe(bls.nmpRspChr, false,
+	if s.nmpRspChr != nil {
+		if err := s.cln.Subscribe(s.nmpRspChr, false,
 			onNotify); err != nil {
 
 			return err
 		}
 	}
 
-	if bls.unauthRspChr != nil {
-		if err := bls.cln.Subscribe(bls.unauthRspChr, false,
+	if s.unauthRspChr != nil {
+		if err := s.cln.Subscribe(s.unauthRspChr, false,
 			onNotify); err != nil {
 
 			return err
@@ -188,57 +203,57 @@ func (bls *BllOicSesn) subscribe() error {
 	return nil
 }
 
-func (bls *BllOicSesn) exchangeMtu() error {
-	mtu, err := exchangeMtu(bls.cln, bls.cfg.PreferredMtu)
+func (s *BllSesn) exchangeMtu() error {
+	mtu, err := exchangeMtu(s.cln, s.cfg.PreferredMtu)
 	if err != nil {
 		return err
 	}
 
-	bls.attMtu = mtu
+	s.attMtu = mtu
 	return nil
 }
 
 // @return bool                 Whether to retry the open attempt; false
 //                                  on success.
 //         error                The cause of a failed open; nil on success.
-func (bls *BllOicSesn) openOnce() (bool, error) {
-	if bls.IsOpen() {
+func (s *BllSesn) openOnce() (bool, error) {
+	if s.IsOpen() {
 		return false, nmxutil.NewSesnAlreadyOpenError(
 			"Attempt to open an already-open bll session")
 	}
 
-	d, err := omp.NewDispatcher(true, 3)
+	txvr, err := mgmt.NewTransceiver(s.cfg.MgmtProto, 3)
 	if err != nil {
 		return false, err
 	}
-	bls.d = d
+	s.txvr = txvr
 
-	if err := bls.connect(); err != nil {
+	if err := s.connect(); err != nil {
 		return false, err
 	}
 
-	if err := bls.exchangeMtu(); err != nil {
+	if err := s.exchangeMtu(); err != nil {
 		return true, err
 	}
 
-	if err := bls.discoverAll(); err != nil {
+	if err := s.discoverAll(); err != nil {
 		return false, err
 	}
 
-	if err := bls.subscribe(); err != nil {
+	if err := s.subscribe(); err != nil {
 		return false, err
 	}
 
 	return false, nil
 }
 
-func (bls *BllOicSesn) Open() error {
+func (s *BllSesn) Open() error {
 	var err error
 
-	for i := 0; i < bls.cfg.ConnTries; i++ {
+	for i := 0; i < s.cfg.ConnTries; i++ {
 		var retry bool
 
-		retry, err = bls.openOnce()
+		retry, err = s.openOnce()
 		if !retry {
 			break
 		}
@@ -246,51 +261,54 @@ func (bls *BllOicSesn) Open() error {
 
 	if err != nil {
 		// Ensure the session is closed.
-		bls.Close()
+		s.Close()
 		return err
 	}
 
 	return nil
 }
 
-func (bls *BllOicSesn) Close() error {
-	if !bls.IsOpen() {
+func (s *BllSesn) Close() error {
+	if !s.IsOpen() {
 		return nmxutil.NewSesnClosedError(
 			"Attempt to close an unopened bll session")
 	}
 
-	if err := bls.cln.CancelConnection(); err != nil {
+	if err := s.cln.CancelConnection(); err != nil {
 		return err
 	}
 
-	bls.cln = nil
+	s.cln = nil
 
 	return nil
 }
 
 // Indicates whether the session is currently open.
-func (bls *BllOicSesn) IsOpen() bool {
-	return bls.cln != nil
+func (s *BllSesn) IsOpen() bool {
+	return s.cln != nil
 }
 
-// Retrieves the maximum data payload for outgoing NMP requests.
-func (bls *BllOicSesn) MtuOut() int {
-	return bls.attMtu - nmble.NOTIFY_CMD_BASE_SZ - nmp.NMP_HDR_SIZE
+// Retrieves the maximum data payload for incoming NMP responses.
+func (s *BllSesn) MtuIn() int {
+	mtu, _ := nmble.MtuIn(s.cfg.MgmtProto, s.attMtu)
+	return mtu
 }
 
-// Retrieves the maximum data payload for incoming NMP responses.
-func (bls *BllOicSesn) MtuIn() int {
-	return bls.attMtu - nmble.NOTIFY_CMD_BASE_SZ - nmp.NMP_HDR_SIZE
+// Retrieves the maximum data payload for outgoing NMP requests.
+func (s *BllSesn) MtuOut() int {
+	mtu, _ := nmble.MtuOut(s.cfg.MgmtProto, s.attMtu)
+	return mtu
 }
 
 // Stops a receive operation in progress.  This must be called from a
 // separate thread, as sesn receive operations are blocking.
-func (bls *BllOicSesn) AbortRx(nmpSeq uint8) error {
-	return bls.d.ErrorOneNmp(nmpSeq, fmt.Errorf("Rx aborted"))
+func (s *BllSesn) AbortRx(nmpSeq uint8) error {
+	s.txvr.ErrorOne(nmpSeq, fmt.Errorf("Rx aborted"))
+	return nil
 }
 
-func (bls *BllOicSesn) EncodeNmpMsg(msg *nmp.NmpMsg) ([]byte, error) {
-	return omp.EncodeOmpTcp(msg)
+func (s *BllSesn) EncodeNmpMsg(msg *nmp.NmpMsg) ([]byte, error) {
+	return nmble.EncodeMgmtMsg(s.cfg.MgmtProto, msg)
 }
 
 // Performs a blocking transmit a single NMP message and listens for the
@@ -298,59 +316,33 @@ func (bls *BllOicSesn) EncodeNmpMsg(msg *nmp.NmpMsg) ([]byte, error) {
 //     * nil: success.
 //     * nmxutil.SesnClosedError: session not open.
 //     * other error
-func (bls *BllOicSesn) TxNmpOnce(msg *nmp.NmpMsg, opt sesn.TxOptions) (
+func (s *BllSesn) TxNmpOnce(msg *nmp.NmpMsg, opt sesn.TxOptions) (
 	nmp.NmpRsp, error) {
 
-	if !bls.IsOpen() {
+	if !s.IsOpen() {
 		return nil, nmxutil.NewSesnClosedError(
 			"Attempt to transmit over closed BLE session")
 	}
 
-	if bls.nmpReqChr == nil || bls.nmpRspChr == nil {
+	if s.nmpReqChr == nil || s.nmpRspChr == nil {
 		return nil, fmt.Errorf("Cannot send NMP request; peer doesn't " +
 			"support request or response characteristic")
 	}
 
-	b, err := bls.EncodeNmpMsg(msg)
-	if err != nil {
-		return nil, err
+	txRaw := func(b []byte) error {
+		return s.cln.WriteCharacteristic(s.nmpReqChr, b, true)
 	}
 
-	nl, err := bls.d.AddNmpListener(msg.Hdr.Seq)
-	if err != nil {
-		return nil, err
-	}
-	defer bls.d.RemoveNmpListener(msg.Hdr.Seq)
-
-	// Send request.
-	if err := bls.cln.WriteCharacteristic(bls.nmpReqChr, b, true); err != nil {
-		return nil, err
-	}
-
-	// Now wait for NMP response.
-	for {
-		select {
-		case err := <-nl.ErrChan:
-			return nil, err
-		case rsp := <-nl.RspChan:
-			return rsp, nil
-		case <-nl.AfterTimeout(opt.Timeout):
-			msg := fmt.Sprintf(
-				"NMP timeout; op=%d group=%d id=%d seq=%d",
-				msg.Hdr.Op, msg.Hdr.Group, msg.Hdr.Id, msg.Hdr.Seq)
-
-			return nil, nmxutil.NewRspTimeoutError(msg)
-		}
-	}
+	return s.txvr.TxNmp(txRaw, msg, opt.Timeout)
 }
 
-func (bls *BllOicSesn) resReqChr(resType sesn.ResourceType) (
+func (s *BllSesn) resReqChr(resType sesn.ResourceType) (
 	*ble.Characteristic, error) {
 
 	m := map[sesn.ResourceType]*ble.Characteristic{
-		sesn.RES_TYPE_PUBLIC: bls.publicReqChr,
-		sesn.RES_TYPE_UNAUTH: bls.unauthReqChr,
-		sesn.RES_TYPE_SECURE: bls.secureReqChr,
+		sesn.RES_TYPE_PUBLIC: s.publicReqChr,
+		sesn.RES_TYPE_UNAUTH: s.unauthReqChr,
+		sesn.RES_TYPE_SECURE: s.secureReqChr,
 	}
 
 	chr := m[resType]
@@ -362,82 +354,58 @@ func (bls *BllOicSesn) resReqChr(resType sesn.ResourceType) (
 	return chr, nil
 }
 
-func (bls *BllOicSesn) GetResourceOnce(resType sesn.ResourceType, uri string,
+func (s *BllSesn) GetResourceOnce(resType sesn.ResourceType, uri string,
 	opt sesn.TxOptions) (coap.COAPCode, []byte, error) {
 
-	chr, err := bls.resReqChr(resType)
+	chr, err := s.resReqChr(resType)
 	if err != nil {
 		return 0, nil, err
 	}
 
 	token := nmxutil.NextToken()
-
-	ol, err := bls.d.AddOicListener(token)
+	req, err := oic.CreateGet(true, uri, token)
 	if err != nil {
 		return 0, nil, err
 	}
-	defer bls.d.RemoveOicListener(token)
 
-	req, err := oic.EncodeGet(true, uri, token)
-	if err != nil {
-		return 0, nil, err
+	txRaw := func(b []byte) error {
+		return s.cln.WriteCharacteristic(chr, b, true)
 	}
 
-	// Send request.
-	if err := bls.cln.WriteCharacteristic(chr, req, true); err != nil {
+	rsp, err := s.txvr.TxOic(txRaw, req, opt.Timeout)
+	if err != nil {
 		return 0, nil, err
-	}
-
-	// Now wait for CoAP response.
-	for {
-		select {
-		case err := <-ol.ErrChan:
-			return 0, nil, err
-		case rsp := <-ol.RspChan:
-			return rsp.Code(), rsp.Payload(), nil
-		case <-ol.AfterTimeout(opt.Timeout):
-			msg := fmt.Sprintf("CoAP timeout; uri=%s", uri)
-			return 0, nil, nmxutil.NewRspTimeoutError(msg)
-		}
+	} else if rsp == nil {
+		return 0, nil, nil
+	} else {
+		return rsp.Code(), rsp.Payload(), nil
 	}
 }
 
-func (bls *BllOicSesn) PutResourceOnce(resType sesn.ResourceType,
+func (s *BllSesn) PutResourceOnce(resType sesn.ResourceType,
 	uri string, value []byte, opt sesn.TxOptions) (coap.COAPCode, error) {
 
-	chr, err := bls.resReqChr(resType)
+	chr, err := s.resReqChr(resType)
 	if err != nil {
 		return 0, err
 	}
 
 	token := nmxutil.NextToken()
-
-	ol, err := bls.d.AddOicListener(token)
+	req, err := oic.CreatePut(true, uri, token, value)
 	if err != nil {
 		return 0, err
 	}
-	defer bls.d.RemoveOicListener(token)
 
-	req, err := oic.EncodePut(true, uri, token, value)
-	if err != nil {
-		return 0, err
+	txRaw := func(b []byte) error {
+		return s.cln.WriteCharacteristic(chr, b, true)
 	}
 
-	// Send request.
-	if err := bls.cln.WriteCharacteristic(chr, req, true); err != nil {
+	rsp, err := s.txvr.TxOic(txRaw, req, opt.Timeout)
+	if err != nil {
 		return 0, err
-	}
-
-	// Now wait for CoAP response.
-	for {
-		select {
-		case err := <-ol.ErrChan:
-			return 0, err
-		case rsp := <-ol.RspChan:
-			return rsp.Code(), nil
-		case <-ol.AfterTimeout(opt.Timeout):
-			msg := fmt.Sprintf("CoAP timeout; uri=%s", uri)
-			return 0, nmxutil.NewRspTimeoutError(msg)
-		}
+	} else if rsp == nil {
+		return 0, nil
+	} else {
+		return rsp.Code(), nil
 	}
 }
diff --git a/newtmgr/bll/bll_sesn_cfg.go b/newtmgr/bll/bll_sesn_cfg.go
index f4660bb..36327cb 100644
--- a/newtmgr/bll/bll_sesn_cfg.go
+++ b/newtmgr/bll/bll_sesn_cfg.go
@@ -32,7 +32,7 @@ import (
 type BllSesnCfg struct {
 	MgmtProto    sesn.MgmtProto
 	AdvFilter    ble.AdvFilter
-	PreferredMtu int
+	PreferredMtu uint16
 	ConnTimeout  time.Duration
 	ConnTries    int
 }
diff --git a/newtmgr/bll/bll_xport.go b/newtmgr/bll/bll_xport.go
index 9bd39b7..56fd4ae 100644
--- a/newtmgr/bll/bll_xport.go
+++ b/newtmgr/bll/bll_xport.go
@@ -58,16 +58,7 @@ func (bx *BllXport) BuildSesn(cfg sesn.SesnCfg) (sesn.Sesn, error) {
 }
 
 func (bx *BllXport) BuildBllSesn(cfg BllSesnCfg) (sesn.Sesn, error) {
-	switch cfg.MgmtProto {
-	case sesn.MGMT_PROTO_NMP:
-		return NewBllPlainSesn(cfg), nil
-	case sesn.MGMT_PROTO_OMP:
-		return NewBllOicSesn(cfg), nil
-	default:
-		return nil, fmt.Errorf(
-			"Invalid management protocol: %d; expected NMP or OMP",
-			cfg.MgmtProto)
-	}
+	return NewBllSesn(cfg), nil
 }
 
 func (bx *BllXport) Start() error {
diff --git a/nmxact/nmble/ble_sesn.go b/nmxact/nmble/ble_sesn.go
index 6d9c889..edbcbb6 100644
--- a/nmxact/nmble/ble_sesn.go
+++ b/nmxact/nmble/ble_sesn.go
@@ -25,13 +25,11 @@ import (
 
 	"github.com/runtimeco/go-coap"
 
-	"mynewt.apache.org/newt/util"
 	. "mynewt.apache.org/newtmgr/nmxact/bledefs"
 	"mynewt.apache.org/newtmgr/nmxact/mgmt"
 	"mynewt.apache.org/newtmgr/nmxact/nmp"
 	"mynewt.apache.org/newtmgr/nmxact/nmxutil"
 	"mynewt.apache.org/newtmgr/nmxact/oic"
-	"mynewt.apache.org/newtmgr/nmxact/omp"
 	"mynewt.apache.org/newtmgr/nmxact/sesn"
 )
 
@@ -98,6 +96,9 @@ func (s *BleSesn) disconnectListen() {
 		nmxutil.Assert(!s.IsOpen())
 
 		// Signal error to all listeners.
+		s.txvr.ErrorAll(err)
+
+		// Stop all go routines.
 		close(s.stopChan)
 		s.wg.Done()
 		s.wg.Wait()
@@ -146,8 +147,7 @@ func (s *BleSesn) notifyListen() {
 
 		for {
 			select {
-			case err := <-nmpRspNl.ErrChan:
-				s.txvr.ErrorAll(err)
+			case <-nmpRspNl.ErrChan:
 				return
 
 			case n, ok := <-nmpRspNl.NotifyChan:
@@ -266,17 +266,7 @@ func (s *BleSesn) IsOpen() bool {
 }
 
 func (s *BleSesn) EncodeNmpMsg(m *nmp.NmpMsg) ([]byte, error) {
-	switch s.cfg.MgmtProto {
-	case sesn.MGMT_PROTO_NMP:
-		return nmp.EncodeNmpPlain(m)
-
-	case sesn.MGMT_PROTO_OMP:
-		return omp.EncodeOmpTcp(m)
-
-	default:
-		return nil,
-			fmt.Errorf("invalid management protocol: %+v", s.cfg.MgmtProto)
-	}
+	return EncodeMgmtMsg(s.cfg.MgmtProto, m)
 }
 
 // Blocking.
@@ -296,18 +286,13 @@ func (s *BleSesn) TxNmpOnce(req *nmp.NmpMsg, opt sesn.TxOptions) (
 }
 
 func (s *BleSesn) MtuIn() int {
-	return s.conn.AttMtu() -
-		NOTIFY_CMD_BASE_SZ -
-		omp.OMP_MSG_OVERHEAD -
-		nmp.NMP_HDR_SIZE
+	mtu, _ := MtuIn(s.cfg.MgmtProto, s.conn.AttMtu())
+	return mtu
 }
 
 func (s *BleSesn) MtuOut() int {
-	mtu := s.conn.AttMtu() -
-		WRITE_CMD_BASE_SZ -
-		omp.OMP_MSG_OVERHEAD -
-		nmp.NMP_HDR_SIZE
-	return util.IntMin(mtu, BLE_ATT_ATTR_MAX_LEN)
+	mtu, _ := MtuOut(s.cfg.MgmtProto, s.conn.AttMtu())
+	return mtu
 }
 
 func (s *BleSesn) ConnInfo() (BleConnDesc, error) {
@@ -336,9 +321,11 @@ func (s *BleSesn) GetResourceOnce(resType sesn.ResourceType, uri string,
 	rsp, err := s.txvr.TxOic(txRaw, req, opt.Timeout)
 	if err != nil {
 		return 0, nil, err
+	} else if rsp == nil {
+		return 0, nil, nil
+	} else {
+		return rsp.Code(), rsp.Payload(), nil
 	}
-
-	return rsp.Code(), rsp.Payload(), nil
 }
 
 func (s *BleSesn) PutResourceOnce(resType sesn.ResourceType,
@@ -363,7 +350,9 @@ func (s *BleSesn) PutResourceOnce(resType sesn.ResourceType,
 	rsp, err := s.txvr.TxOic(txRaw, req, opt.Timeout)
 	if err != nil {
 		return 0, err
+	} else if rsp == nil {
+		return 0, nil
+	} else {
+		return rsp.Code(), nil
 	}
-
-	return rsp.Code(), nil
 }
diff --git a/nmxact/nmble/ble_util.go b/nmxact/nmble/ble_util.go
index 0f530e3..932cb30 100644
--- a/nmxact/nmble/ble_util.go
+++ b/nmxact/nmble/ble_util.go
@@ -27,9 +27,12 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 
+	"mynewt.apache.org/newt/util"
 	. "mynewt.apache.org/newtmgr/nmxact/bledefs"
+	"mynewt.apache.org/newtmgr/nmxact/nmp"
 	"mynewt.apache.org/newtmgr/nmxact/nmxutil"
 	"mynewt.apache.org/newtmgr/nmxact/oic"
+	"mynewt.apache.org/newtmgr/nmxact/omp"
 	"mynewt.apache.org/newtmgr/nmxact/sesn"
 )
 
@@ -770,3 +773,53 @@ func BuildMgmtChrs(mgmtProto sesn.MgmtProto) (BleMgmtChrs, error) {
 
 	return mgmtChrs, nil
 }
+
+func MtuIn(mgmtProto sesn.MgmtProto, attMtu uint16) (int, error) {
+	var mtu int
+
+	switch mgmtProto {
+	case sesn.MGMT_PROTO_NMP:
+		mtu = int(attMtu) - NOTIFY_CMD_BASE_SZ - nmp.NMP_HDR_SIZE
+
+	case sesn.MGMT_PROTO_OMP:
+		mtu = int(attMtu) - NOTIFY_CMD_BASE_SZ - omp.OMP_MSG_OVERHEAD -
+			nmp.NMP_HDR_SIZE
+
+	default:
+		return 0, fmt.Errorf("Invalid management protocol: %s", mgmtProto)
+	}
+
+	return mtu, nil
+}
+
+func MtuOut(mgmtProto sesn.MgmtProto, attMtu uint16) (int, error) {
+	var mtu int
+
+	switch mgmtProto {
+	case sesn.MGMT_PROTO_NMP:
+		mtu = int(attMtu) - NOTIFY_CMD_BASE_SZ - nmp.NMP_HDR_SIZE
+
+	case sesn.MGMT_PROTO_OMP:
+		mtu = int(attMtu) - NOTIFY_CMD_BASE_SZ - omp.OMP_MSG_OVERHEAD -
+			nmp.NMP_HDR_SIZE
+
+	default:
+		return 0, fmt.Errorf("Invalid management protocol: %s", mgmtProto)
+	}
+
+	return util.IntMin(mtu, BLE_ATT_ATTR_MAX_LEN), nil
+}
+
+func EncodeMgmtMsg(mgmtProto sesn.MgmtProto, m *nmp.NmpMsg) ([]byte, error) {
+	switch mgmtProto {
+	case sesn.MGMT_PROTO_NMP:
+		return nmp.EncodeNmpPlain(m)
+
+	case sesn.MGMT_PROTO_OMP:
+		return omp.EncodeOmpTcp(m)
+
+	default:
+		return nil,
+			fmt.Errorf("invalid management protocol: %+v", mgmtProto)
+	}
+}
diff --git a/nmxact/nmble/conn.go b/nmxact/nmble/conn.go
index bf8fd10..36a147f 100644
--- a/nmxact/nmble/conn.go
+++ b/nmxact/nmble/conn.go
@@ -32,7 +32,7 @@ func NewNotifyListener() *NotifyListener {
 type Conn struct {
 	bx      *BleXport
 	rxvr    *Receiver
-	attMtu  int
+	attMtu  uint16
 	profile Profile
 	desc    BleConnDesc
 
@@ -153,7 +153,7 @@ func (c *Conn) eventListen(bl *Listener) error {
 					} else {
 						log.Debugf("BLE ATT MTU updated; from=%d to=%d",
 							c.attMtu, msg.Mtu)
-						c.attMtu = int(msg.Mtu)
+						c.attMtu = msg.Mtu
 					}
 
 				case *BleEncChangeEvt:
@@ -369,7 +369,7 @@ func (c *Conn) ConnInfo() BleConnDesc {
 	return c.desc
 }
 
-func (c *Conn) AttMtu() int {
+func (c *Conn) AttMtu() uint16 {
 	return c.attMtu
 }
 
@@ -558,7 +558,7 @@ func (c *Conn) ExchangeMtu() error {
 		return err
 	}
 
-	c.attMtu = mtu
+	c.attMtu = uint16(mtu)
 	return nil
 }
 

-- 
To stop receiving notification emails like this one, please contact
"commits@mynewt.apache.org" <co...@mynewt.apache.org>.