Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.1.2-dev
3.1.2
10 changes: 9 additions & 1 deletion ngap/dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,15 @@ func Dispatch(conn net.Conn, msg []byte) {

ran, ok := amfSelf.AmfRanFindByConn(conn)
if !ok {
logger.NgapLog.Infof("Create a new NG connection for: %s", conn.RemoteAddr().String())
if len(msg) == 0 {
// No existing RAN context for this connection: either the connection
// closed before any NGAP message arrived, or an SCTP notification
// already triggered ran.Remove(). Skip creating a transient context.
logger.NgapLog.Debugf("RAN context not found for closing connection[addr: %+v], nothing to remove",
conn.RemoteAddr())
return
}
Comment thread
gab-arrobo marked this conversation as resolved.
logger.NgapLog.Infof("Create a new NG connection for: %+v", conn.RemoteAddr())
ran = amfSelf.NewAmfRan(conn)
}

Expand Down
39 changes: 39 additions & 0 deletions ngap/dispatcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,31 @@ package ngap

import (
ctxt "context"
"net"
"testing"
"time"

"github.com/omec-project/amf/context"
"github.com/omec-project/amf/protos/sdcoreAmfServer"
)

// mockConn is a minimal net.Conn used to exercise Dispatch without a real SCTP socket.
type mockConn struct{}

type mockAddr struct{}

func (a mockAddr) Network() string { return "sctp" }
func (a mockAddr) String() string { return "192.0.2.1:38412" }

func (c *mockConn) RemoteAddr() net.Addr { return mockAddr{} }
func (c *mockConn) LocalAddr() net.Addr { return mockAddr{} }
func (c *mockConn) Read(_ []byte) (int, error) { return 0, net.ErrClosed }
func (c *mockConn) Write(_ []byte) (int, error) { return 0, net.ErrClosed }
func (c *mockConn) Close() error { return nil }
func (c *mockConn) SetDeadline(_ time.Time) error { return nil }
func (c *mockConn) SetReadDeadline(_ time.Time) error { return nil }
func (c *mockConn) SetWriteDeadline(_ time.Time) error { return nil }

func TestDispatchLbIgnoresMissingRanContext(t *testing.T) {
msg := &sdcoreAmfServer.SctplbMessage{
Msg: []byte{0x00},
Expand All @@ -38,3 +57,23 @@ func TestDispatchNgapMsgIgnoresNilPdu(t *testing.T) {

DispatchNgapMsg(ctxt.Background(), ran, nil, nil)
}

// TestDispatchEmptyMsgUnknownConnDoesNotPanic verifies that Dispatch does not panic
// and does not create an AmfRan entry when it receives an empty (connection-close)
// message for a connection that has no existing RAN context.
func TestDispatchEmptyMsgUnknownConnDoesNotPanic(t *testing.T) {
conn := &mockConn{}

defer func() {
if r := recover(); r != nil {
t.Fatalf("Dispatch panicked with empty message and unknown conn: %v", r)
}
}()

Dispatch(conn, nil)

// Confirm that no AmfRan was created in the pool for this unknown connection.
if _, ok := context.AMF_Self().AmfRanFindByConn(conn); ok {
t.Error("Dispatch must not create an AmfRan for an unknown connection with an empty message")
}
}
8 changes: 7 additions & 1 deletion ngap/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func listenAndServe(addr *sctp.SCTPAddr, handler NGAPHandler) {
logger.NgapLog.Debugf("set read timeout: %+v", readTimeout)
}

logger.NgapLog.Infof("[AMF] SCTP Accept from: %s", newConn.RemoteAddr().String())
logger.NgapLog.Infof("[AMF] SCTP Accept from: %+v", newConn.RemoteAddr())
connections.Store(newConn, true)

go handleConnection(newConn, readBufSize, handler)
Expand Down Expand Up @@ -196,6 +196,12 @@ func handleConnection(conn *sctp.SCTPConn, bufsize uint32, handler NGAPHandler)
defer func() {
connections.Delete(conn)

// Notify the NGAP dispatcher that this RAN connection has closed so that
// its AmfRan entry is removed from AmfRanPool
if handler.HandleMessage != nil {
handler.HandleMessage(conn, nil)
}
Comment thread
gab-arrobo marked this conversation as resolved.

// if AMF call Stop(), then conn.Close() will return EBADF because conn has been closed inside Stop()
if err := conn.Close(); err != nil && err != syscall.EBADF {
logger.NgapLog.Errorf("close connection error: %+v", err)
Expand Down
Loading