Skip to content

Commit

Permalink
fix: update stcp and remove unused line
Browse files Browse the repository at this point in the history
  • Loading branch information
tim1207 committed Apr 27, 2024
2 parents af79b35 + 96b4f33 commit 4b0a5f8
Show file tree
Hide file tree
Showing 20 changed files with 326 additions and 66 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/commit-msg-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: 'Commit Message Check'

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:
name: Conventional Commits
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: webiny/[email protected]
2 changes: 1 addition & 1 deletion .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
go langname: golangci-lint
name: golangci-lint

on:
push:
Expand Down
5 changes: 2 additions & 3 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ run:
# output configuration options
output:
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
format: colored-line-number
formats: colored-line-number
# print lines of code with issue, default is true
print-issued-lines: true
# print linter name in the end of issue text, default is true
Expand Down Expand Up @@ -161,9 +161,8 @@ linters-settings:
# enable or disable analyzers by name
enable:
- atomicalign
enable-all: false
disable:
- shadow
enable-all: false
disable-all: false
depguard:
list-type: blacklist
Expand Down
2 changes: 1 addition & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func action(cliCtx *cli.Context) error {
callback.SendAmfStatusChangeNotify((string)(models.StatusChange_UNAVAILABLE), amfSelf.ServedGuamiList)
}

amf, err := service.NewApp(cfg, ([]func(*service.AmfApp){appStart, appStop}))
amf, err := service.NewApp(cfg, appStart, appStop)
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/free5gc/nas v1.1.3
github.com/free5gc/ngap v1.0.8
github.com/free5gc/openapi v1.0.8
github.com/free5gc/sctp v1.0.0
github.com/free5gc/sctp v1.0.1
github.com/free5gc/util v1.0.6
github.com/gin-contrib/cors v1.7.1
github.com/gin-gonic/gin v1.9.1
Expand Down Expand Up @@ -57,6 +57,7 @@ require (
github.com/tim-ywliu/nested-logrus-formatter v1.3.2 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/net v0.24.0 // indirect
Expand Down
6 changes: 5 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ github.com/free5gc/openapi v1.0.8 h1:QjfQdB6VVA1GRnzOJ7nILzrI7gMiY0lH64JHVW7vF34
github.com/free5gc/openapi v1.0.8/go.mod h1:w6y9P/uySczc1d9OJZAEuB2FImR/z60Wg2BekPAVt3M=
github.com/free5gc/sctp v1.0.0 h1:V868MT9yyF2I8uotLCEjLULmhTzrLKxPBvsqFk82xGI=
github.com/free5gc/sctp v1.0.0/go.mod h1:3wEzH3L0tljQCLaqEqEalLdW2290B8D5Aw4orsKHxUs=
github.com/free5gc/sctp v1.0.1 h1:g8WDO97r8B9ubkT5Hyk9b4I1fZUOii9Z39gQ2eRaASo=
github.com/free5gc/sctp v1.0.1/go.mod h1:7QXfRWCmlkBGD0EIu3qL5o71bslfIakydz4h2QDZdjQ=
github.com/free5gc/util v1.0.6 h1:dBt9drcXtYKE/cY5XuQcuffgsYclPIpIArhSeS6M+DQ=
github.com/free5gc/util v1.0.6/go.mod h1:eSGN7POUM8LNTvg/E591XR6447a6/w1jFWGKNZPHcXw=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
Expand Down Expand Up @@ -127,6 +129,8 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk=
github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
Expand Down Expand Up @@ -156,4 +160,4 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
51 changes: 29 additions & 22 deletions internal/gmm/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import (
"github.com/pkg/errors"

"github.com/free5gc/amf/internal/context"
gmm_common "github.com/free5gc/amf/internal/gmm/common"
gmm_message "github.com/free5gc/amf/internal/gmm/message"
"github.com/free5gc/amf/internal/logger"
ngap_message "github.com/free5gc/amf/internal/ngap/message"
"github.com/free5gc/amf/internal/sbi/producer/callback"
"github.com/free5gc/amf/internal/util"
"github.com/free5gc/amf/pkg/factory"
Expand All @@ -33,10 +36,6 @@ import (
"github.com/free5gc/openapi/Nnrf_NFDiscovery"
"github.com/free5gc/openapi/models"
"github.com/free5gc/util/fsm"

gmm_common "github.com/free5gc/amf/internal/gmm/common"
gmm_message "github.com/free5gc/amf/internal/gmm/message"
ngap_message "github.com/free5gc/amf/internal/ngap/message"
)

const psiArraySize = 16
Expand Down Expand Up @@ -261,7 +260,8 @@ func CreatePDUSession(ulNasTransport *nasMessage.ULNASTransport,
}
}

if newSmContext, cause, err := service.GetApp().Consumer().SelectSmf(ue, anType, pduSessionID, snssai, dnn); err != nil {
if newSmContext, cause, err := service.GetApp().Consumer().SelectSmf(
ue, anType, pduSessionID, snssai, dnn); err != nil {
ue.GmmLog.Errorf("Select SMF failed: %+v", err)
gmm_message.SendDLNASTransport(ue.RanUe[anType], nasMessage.PayloadContainerTypeN1SMInfo,
smMessage, pduSessionID, cause, nil, 0)
Expand Down Expand Up @@ -592,15 +592,16 @@ func contextTransferFromOldAmf(ue *context.AmfUe, anType models.AccessType, oldA
case nasMessage.RegistrationType5GSPeriodicRegistrationUpdating:
transferReason = models.TransferReason_MOBI_REG
}
ueContextTransferRspData, problemDetails, err := service.GetApp().Consumer().UEContextTransferRequest(ue, anType, transferReason)
if problemDetails != nil {
if problemDetails.Cause == "INTEGRITY_CHECK_FAIL" || problemDetails.Cause == "CONTEXT_NOT_FOUND" {

ueContextTransferRspData, pd, err := service.GetApp().Consumer().UEContextTransferRequest(ue, anType, transferReason)
if pd != nil {
if pd.Cause == "INTEGRITY_CHECK_FAIL" || pd.Cause == "CONTEXT_NOT_FOUND" {
// TODO 9a. After successful authentication in new AMF, which is triggered by the integrity check failure
// in old AMF at step 5, the new AMF invokes step 4 above again and indicates that the UE is validated
//(i.e. through the reason parameter as specified in clause 5.2.2.2.2).
return fmt.Errorf("Can not retrieve UE Context from old AMF[Cause: %s]", problemDetails.Cause)
return fmt.Errorf("Can not retrieve UE Context from old AMF[Cause: %s]", pd.Cause)
}
return fmt.Errorf("UE Context Transfer Request Failed Problem[%+v]", problemDetails)
return fmt.Errorf("UE Context Transfer Request Failed Problem[%+v]", pd)
} else if err != nil {
return fmt.Errorf("UE Context Transfer Request Error[%+v]", err)
} else {
Expand Down Expand Up @@ -702,7 +703,8 @@ func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) erro

// }
for {
resp, err := service.GetApp().Consumer().SendSearchNFInstances(amfSelf.NrfUri, models.NfType_PCF, models.NfType_AMF, &param)
resp, err := service.GetApp().Consumer().SendSearchNFInstances(
amfSelf.NrfUri, models.NfType_PCF, models.NfType_AMF, &param)
if err != nil {
ue.GmmLog.Error("AMF can not select an PCF by NRF")
} else {
Expand Down Expand Up @@ -1007,7 +1009,8 @@ func communicateWithUDM(ue *context.AmfUe, accessType models.AccessType) error {
param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{
Supi: optional.NewString(ue.Supi),
}
resp, err := service.GetApp().Consumer().SendSearchNFInstances(amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, &param)
resp, err := service.GetApp().Consumer().SendSearchNFInstances(
amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, &param)
if err != nil {
return errors.Errorf("AMF can not select an UDM by NRF: SendSearchNFInstances failed")
}
Expand Down Expand Up @@ -1076,7 +1079,8 @@ func getSubscribedNssai(ue *context.AmfUe) {
Supi: optional.NewString(ue.Supi),
}
for {
err := service.GetApp().Consumer().SearchUdmSdmInstance(ue, amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, &param)
err := service.GetApp().Consumer().SearchUdmSdmInstance(
ue, amfSelf.NrfUri, models.NfType_UDM, models.NfType_AMF, &param)
if err != nil {
ue.GmmLog.Errorf("AMF can not select an Nudm_SDM Instance by NRF[Error: %+v]", err)
time.Sleep(2 * time.Second)
Expand Down Expand Up @@ -1139,7 +1143,8 @@ func handleRequestedNssai(ue *context.AmfUe, anType models.AccessType) error {
if needSliceSelection {
if ue.NssfUri == "" {
for {
err := service.GetApp().Consumer().SearchNssfNSSelectionInstance(ue, amfSelf.NrfUri, models.NfType_NSSF, models.NfType_AMF, nil)
err := service.GetApp().Consumer().SearchNssfNSSelectionInstance(
ue, amfSelf.NrfUri, models.NfType_NSSF, models.NfType_AMF, nil)
if err != nil {
ue.GmmLog.Errorf("AMF can not select an NSSF Instance by NRF[Error: %+v]", err)
time.Sleep(2 * time.Second)
Expand Down Expand Up @@ -1648,7 +1653,8 @@ func AuthenticationProcedure(ue *context.AmfUe, accessType models.AccessType) (b

// TODO: consider ausf group id, Routing ID part of SUCI
param := Nnrf_NFDiscovery.SearchNFInstancesParamOpts{}
resp, err := service.GetApp().Consumer().SendSearchNFInstances(amfSelf.NrfUri, models.NfType_AUSF, models.NfType_AMF, &param)
resp, err := service.GetApp().Consumer().SendSearchNFInstances(
amfSelf.NrfUri, models.NfType_AUSF, models.NfType_AMF, &param)
if err != nil {
ue.GmmLog.Error("AMF can not select an AUSF by NRF")
gmm_message.SendRegistrationReject(ue.RanUe[accessType], nasMessage.Cause5GMMCongestion, "")
Expand Down Expand Up @@ -1984,7 +1990,8 @@ func HandleAuthenticationResponse(ue *context.AmfUe, accessType models.AccessTyp
}
}

response, problemDetails, err := service.GetApp().Consumer().SendAuth5gAkaConfirmRequest(ue, hex.EncodeToString(resStar[:]))
response, problemDetails, err := service.GetApp().Consumer().SendAuth5gAkaConfirmRequest(
ue, hex.EncodeToString(resStar[:]))
if err != nil {
return err
} else if problemDetails != nil {
Expand Down Expand Up @@ -2018,11 +2025,11 @@ func HandleAuthenticationResponse(ue *context.AmfUe, accessType models.AccessTyp
}
}
case models.AuthType_EAP_AKA_PRIME:
response, problemDetails, err := service.GetApp().Consumer().SendEapAuthConfirmRequest(ue, *authenticationResponse.EAPMessage)
response, pd, err := service.GetApp().Consumer().SendEapAuthConfirmRequest(ue, *authenticationResponse.EAPMessage)
if err != nil {
return err
} else if problemDetails != nil {
ue.GmmLog.Debugf("EapAuthConfirm Error[Problem Detail: %+v]", problemDetails)
} else if pd != nil {
ue.GmmLog.Debugf("EapAuthConfirm Error[Problem Detail: %+v]", pd)
return nil
}

Expand Down Expand Up @@ -2153,11 +2160,11 @@ func HandleAuthenticationFailure(ue *context.AmfUe, anType models.AccessType,
Rand: av5gAka.Rand,
}

response, problemDetails, err := service.GetApp().Consumer().SendUEAuthenticationAuthenticateRequest(ue, resynchronizationInfo)
response, pd, err := service.GetApp().Consumer().SendUEAuthenticationAuthenticateRequest(ue, resynchronizationInfo)
if err != nil {
return err
} else if problemDetails != nil {
ue.GmmLog.Errorf("Nausf_UEAU Authenticate Request Error[Problem Detail: %+v]", problemDetails)
} else if pd != nil {
ue.GmmLog.Errorf("Nausf_UEAU Authenticate Request Error[Problem Detail: %+v]", pd)
return nil
}
ue.AuthenticationCtx = response
Expand Down
14 changes: 14 additions & 0 deletions internal/nas/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import (
"testing"

"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"

amf_context "github.com/free5gc/amf/internal/context"
"github.com/free5gc/amf/internal/logger"
amf_nas "github.com/free5gc/amf/internal/nas"
"github.com/free5gc/amf/internal/sbi/consumer"
"github.com/free5gc/amf/pkg/service"
"github.com/free5gc/nas"
"github.com/free5gc/nas/nasMessage"
"github.com/free5gc/nas/nasType"
Expand Down Expand Up @@ -129,6 +132,7 @@ func FuzzHandleNAS2(f *testing.F) {
Tac: "1",
}
amfSelf.SupportTaiLists = []models.Tai{tai}
amfSelf.NrfUri = "test"

msg := nas.NewMessage()
msg.GmmMessage = nas.NewGmmMessage()
Expand Down Expand Up @@ -211,6 +215,16 @@ func FuzzHandleNAS2(f *testing.F) {
f.Add(buf)

f.Fuzz(func(t *testing.T, d []byte) {
ctrl := gomock.NewController(t)
m := service.NewMockApp(ctrl)
service.AMF = m
c, err := consumer.NewConsumer(m)
require.NoError(t, err)
m.EXPECT().
Consumer().
AnyTimes().
Return(c)

ue := new(amf_context.RanUe)
ue.Ran = new(amf_context.AmfRan)
ue.Ran.AnType = models.AccessType__3_GPP_ACCESS
Expand Down
1 change: 0 additions & 1 deletion internal/nas/nas_security/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@ func Decode(ue *context.AmfUe, accessType models.AccessType, payload []byte,
}

err = msg.PlainNasDecode(&payload)

if err != nil {
return nil, false, err
}
Expand Down
10 changes: 5 additions & 5 deletions internal/ngap/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1093,10 +1093,10 @@ func handleUEContextReleaseRequestMain(ran *context.AmfRan,
// TODO: Check if doing error handling here
continue
}
response, _, _, err := service.GetApp().Consumer().SendUpdateSmContextDeactivateUpCnxState(amfUe, smContext, causeAll)
rsp, _, _, err := service.GetApp().Consumer().SendUpdateSmContextDeactivateUpCnxState(amfUe, smContext, causeAll)
if err != nil {
ranUe.Log.Errorf("Send Update SmContextDeactivate UpCnxState Error[%s]", err.Error())
} else if response == nil {
} else if rsp == nil {
ranUe.Log.Errorln("Send Update SmContextDeactivate UpCnxState Error")
}
}
Expand Down Expand Up @@ -1406,18 +1406,18 @@ func handleHandoverRequestAcknowledgeMain(ran *context.AmfRan,
// TODO: Check if doing error handling here
continue
}
response, errResponse, problemDetails, err := service.GetApp().Consumer().SendUpdateSmContextN2HandoverPrepared(amfUe,
resp, errResponse, problemDetails, err := service.GetApp().Consumer().SendUpdateSmContextN2HandoverPrepared(amfUe,
smContext, models.N2SmInfoType_HANDOVER_REQ_ACK, transfer)
if err != nil {
targetUe.Log.Errorf("Send HandoverRequestAcknowledgeTransfer error: %v", err)
}
if problemDetails != nil {
targetUe.Log.Warnf("ProblemDetails[status: %d, Cause: %s]", problemDetails.Status, problemDetails.Cause)
}
if response != nil && response.BinaryDataN2SmInformation != nil {
if resp != nil && resp.BinaryDataN2SmInformation != nil {
handoverItem := ngapType.PDUSessionResourceHandoverItem{}
handoverItem.PDUSessionID = item.PDUSessionID
handoverItem.HandoverCommandTransfer = response.BinaryDataN2SmInformation
handoverItem.HandoverCommandTransfer = resp.BinaryDataN2SmInformation
pduSessionResourceHandoverList.List = append(pduSessionResourceHandoverList.List, handoverItem)
targetUe.SuccessPduSessionId = append(targetUe.SuccessPduSessionId, pduSessionID)
}
Expand Down
16 changes: 15 additions & 1 deletion internal/sbi/consumer/amf_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ func (s *namfService) BuildUeContextModel(ue *amf_context.AmfUe) (ueContext mode
return ueContext
}

func (s *namfService) buildAmPolicyReqTriggers(triggers []models.RequestTrigger) (amPolicyReqTriggers []models.AmPolicyReqTrigger) {
func (s *namfService) buildAmPolicyReqTriggers(
triggers []models.RequestTrigger,
) (amPolicyReqTriggers []models.AmPolicyReqTrigger) {
for _, trigger := range triggers {
switch trigger {
case models.RequestTrigger_LOC_CH:
Expand All @@ -148,6 +150,9 @@ func (s *namfService) CreateUEContextRequest(ue *amf_context.AmfUe, ueContextCre
ueContextCreatedData *models.UeContextCreatedData, problemDetails *models.ProblemDetails, err error,
) {
client := s.getComClient(ue.TargetAmfUri)
if client == nil {
return nil, nil, openapi.ReportError("amf not found")
}

req := models.CreateUeContextRequest{
JsonData: &ueContextCreateData,
Expand Down Expand Up @@ -185,6 +190,9 @@ func (s *namfService) ReleaseUEContextRequest(ue *amf_context.AmfUe, ngapCause m
problemDetails *models.ProblemDetails, err error,
) {
client := s.getComClient(ue.TargetAmfUri)
if client == nil {
return nil, openapi.ReportError("amf not found")
}

var ueContextId string
if ue.Supi != "" {
Expand Down Expand Up @@ -234,6 +242,9 @@ func (s *namfService) UEContextTransferRequest(
ueContextTransferRspData *models.UeContextTransferRspData, problemDetails *models.ProblemDetails, err error,
) {
client := s.getComClient(ue.TargetAmfUri)
if client == nil {
return nil, nil, openapi.ReportError("amf not found")
}

ueContextTransferReqData := models.UeContextTransferReqData{
Reason: transferReason,
Expand Down Expand Up @@ -289,6 +300,9 @@ func (s *namfService) RegistrationStatusUpdate(ue *amf_context.AmfUe, request mo
regStatusTransferComplete bool, problemDetails *models.ProblemDetails, err error,
) {
client := s.getComClient(ue.TargetAmfUri)
if client == nil {
return false, nil, openapi.ReportError("amf not found")
}

ueContextId := fmt.Sprintf("5g-guti-%s", ue.Guti)

Expand Down
9 changes: 9 additions & 0 deletions internal/sbi/consumer/ausf_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func (s *nausfService) SendUEAuthenticationAuthenticateRequest(ue *amf_context.A
resynchronizationInfo *models.ResynchronizationInfo,
) (*models.UeAuthenticationCtx, *models.ProblemDetails, error) {
client := s.getUEAuthenticationClient(ue.AusfUri)
if client == nil {
return nil, nil, openapi.ReportError("ausf not found")
}

amfSelf := amf_context.GetSelf()
servedGuami := amfSelf.ServedGuamiList[0]
Expand Down Expand Up @@ -103,6 +106,9 @@ func (s *nausfService) SendAuth5gAkaConfirmRequest(ue *amf_context.AmfUe, resSta
}

client := s.getUEAuthenticationClient(ausfUri)
if client == nil {
return nil, nil, openapi.ReportError("ausf not found")
}

confirmData := &Nausf_UEAuthentication.UeAuthenticationsAuthCtxId5gAkaConfirmationPutParamOpts{
ConfirmationData: optional.NewInterface(models.ConfirmationData{
Expand Down Expand Up @@ -151,6 +157,9 @@ func (s *nausfService) SendEapAuthConfirmRequest(ue *amf_context.AmfUe, eapMsg n
ausfUri := fmt.Sprintf("%s://%s", confirmUri.Scheme, confirmUri.Host)

client := s.getUEAuthenticationClient(ausfUri)
if client == nil {
return nil, nil, openapi.ReportError("ausf not found")
}

eapSessionReq := &Nausf_UEAuthentication.EapAuthMethodParamOpts{
EapSession: optional.NewInterface(models.EapSession{
Expand Down
Loading

0 comments on commit 4b0a5f8

Please sign in to comment.