changed 7 months ago
Linked with GitHub

Capture packets

Information in wireshark

RAND value

AUTN value

GO language

  • 看要不要獨立一篇出來
  • chatgpt之前問的問題要紀錄下來

main.go / init.go

image
image
image

Example in Free5GC

  • You can find that there are some building logs when you run the run.sh, and they are really start from run.sh.
    image
    • After it do something, start UPF and MongoDB, it will run every NF in ~/bin/NF and read the config of them.
      image
      image
  • If you see the log in detail, you can find some descreption of each NF, and it is not from run.sh because run.sh is done.
    image
    • About the files in bin folder, we can not read it because of the garbled characters.
      image
      image
    • About the explanation of these files.
      image
      image
    • So after bin file is executed, system will enter main.go and it will call init.go, then in this process, you can the logs is printed from here.
      image
      image
  • In init.go, you can see it imports a lot of service
    image
    • And call some functions which will print out the logs.
      image
      image
      image
      image
      image

Go module

Example before

  • Link
  • Compared to my study on Terry's method.

go.mod

  • I want to clearify the usage of this, because this is one of the point in the newer version(>1.11) of Go language, most of the import methods don't rely on GOPATH.
  • When I was browsing my past method and Terry's, I found that there is no a direct URL calling the Network Function in each go.mod, but it exists on the first line.
    image
    • For ex, there is no 1 and 2 in go.mod, but for 3 there are in go.mod, which means I can directly import the things in the same amf folder.
      image

Answar

image
image
image
image

go mod init github.com/yourusername/yourproject

image
image
image
image
image
image

Test

image
image
image

replace

  • Before I know how Terry use the import, I dont understand why he doesnt use replace in go.mod to redirect the URL but he can import his own local folder.
    • Here is some concept of replace.
      image
      image
      image
      image
      image
    • So the point is that there has already a URL which calls the resouce from github, and we use "replace" to cut the link with github, rebuild a link with local folder/file if we want to do a test in local environment.
    • Then what I had done using replace may be an unnecessory move, because the OG URL has already call the folder I want to use, and replace just add one more command to call the local path.
      image

The environment path check

image

Some other possibility

image

go env GOPATH //This command is also useful for check the location.

image

go list -m all

image
image
image
image

import

import( github.com/ )

  • When I was modifying the UDM/UDR part in AUSF improvement, I found that there is no this imported address in the local free5gc folder (free5gc/util/).
    image
  • But it is indeed in the go.mod in UDR.
    image
  • The answar is in the repository on free5GC official github, the URL will be the same as what you import when you click into one of the repo.
    image

Use code from github

reference

https://blog.csdn.net/yeshang_lady/article/details/134272955
https://home.gamer.com.tw/artwork.php?sn=5463024
image

Code

  • In smf, take sm_context.go in package context as example, below are the functions it import, some are the functions from the official go language, the other imported lines including "github.com/" are from the github of free5gc.
    image
    image

  • You can see the reference about how you can add the frepository into your code, in free5gc's NFs, every NF has a file called go.mod, recording the url it imports.
    image

  • Until here, Im curious about if the free5gc works without internet, because the modules from github are imported, not copied to local host, so I do a test closing the network interface and running the 5gc.
    The result is that it needs addresses binded for using http service, but it doesnt explan whether the github module affect the program.
    image

Use code from local place

reference

https://calvertyang.github.io/2019/11/12/a-beginners-guide-to-packages-in-golang/

Package context

image
image
image

Package

image
image
image

GOPATH

  • Check the path in your environment, it will be void if you havent set GOPATH.
    • The default path will be $HOME/go if your version >= Go 1.11
echo $GOPATH
  • Set the path.
    • It will not affect other path directly, GOPATH is used for store 3rd party packages or items, and dealing with the improting relation in Go, it will tell compiler where to find and check the library.
    • Other package provided by Go standard library exist when installing Go, and can be accessed everywhere.
export GOPATH=/home/ubuntu/free5gc_AUSF_v2.0

make

image

image

image

Run .go in VScode

image
image

package main import ( "fmt" "strings" ) func main() { suci := "suci-0-208-93-0000-0-0-0000000003" parts := strings.Split(suci, "-") lastPart := parts[len(parts)-1] supi := "imsi-20893" + lastPart fmt.Println(supi) // 輸出: imsi-208930000000003 }

image

go mod init example.com/myapp

image

go run main.go

image

Set the environment PATH for Go

  • Error when I want to go run.
go : 無法辨識 'go' 詞彙是否為 Cmdlet、函數、指令檔或可執行程式的名稱。請檢查名稱拼字是否正確,如果包含路徑的話,請確認路徑是否正
確,然後再試一次。
位於 線路:1 字元:1
+ go run main.go
+ ~~
    + CategoryInfo          : ObjectNotFound: (go:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
  • Usually after the installation, the PATH of Go will be added automatically, like the pic below, I added it repeatly.
    image
  • The reason why this error popped up is that I need to restart the VScode after installing Go, after restart :
    image
    image

image
image

go version

image
image

const

// suci-0(SUPI type: IMSI)-mcc-mnc-routingIndicator-protectionScheme-homeNetworkPublicKeyID-schemeOutput. // TODO: // suci-1(SUPI type: NAI)-homeNetworkID-routingIndicator-protectionScheme-homeNetworkPublicKeyID-schemeOutput. const ( PrefixPlace = iota SupiTypePlace MccPlace MncPlace RoutingIndicatorPlace SchemePlace HNPublicKeyIDPlace SchemeOuputPlace MaxPlace ) const ( PrefixIMSI = "imsi-" PrefixSUCI = "suci" SupiTypeIMSI = "0" NullScheme = "0" ProfileAScheme = "1" ProfileBScheme = "2" ) func ToSupi(suci string, suciProfiles []SuciProfile) (string, error) { suciPart := strings.Split(suci, "-") logger.SuciLog.Infof("suciPart: %+v", suciPart) suciPrefix := suciPart[0] if suciPrefix == "imsi" || suciPrefix == "nai" { logger.SuciLog.Infof("Got supi\n") return suci, nil } else if suciPrefix == PrefixSUCI { if len(suciPart) < 6 { return "", fmt.Errorf("Suci with wrong format\n") } } else { return "", fmt.Errorf("Unknown suciPrefix [%s]", suciPrefix) } logger.SuciLog.Infof("scheme %s\n", suciPart[SchemePlace]) scheme := suciPart[SchemePlace] mccMnc := suciPart[MccPlace] + suciPart[MncPlace] supiPrefix := PrefixIMSI if suciPrefix == PrefixSUCI && suciPart[SupiTypePlace] == SupiTypeIMSI { logger.SuciLog.Infof("SUPI type is IMSI\n") } if scheme == NullScheme { // NULL scheme return supiPrefix + mccMnc + suciPart[len(suciPart)-1], nil } . . .
  • How ToSupi can use the variable MccPlace or MncPlace without calling ?

image
image
image

image
image
image

P0 := []byte(snName)

image

package main import "fmt" func main() { snName := "Hello, Go!" P0 := []byte(snName) fmt.Println("Original string:", snName) fmt.Println("Byte slice:", P0) }

image

Return

return "" & return nil

image

package main import "fmt" func getEmptyString() string { return "" } func main() { result := getEmptyString() fmt.Println(result) // 輸出一個空行,因為 result 是一個空字符串 }

image
image
image

package main import "fmt" // 返回空字符串 func getEmptyString() string { return "" } // 返回空指針 func getNilPointer() *int { return nil } // 返回空切片 func getNilSlice() []int { return nil } // 返回空映射 func getNilMap() map[string]int { return nil } // 返回空通道 func getNilChannel() chan int { return nil } // 返回空接口 func getNilInterface() interface{} { return nil } func main() { fmt.Println("Empty String:", getEmptyString()) fmt.Println("Nil Pointer:", getNilPointer()) fmt.Println("Nil Slice:", getNilSlice()) fmt.Println("Nil Map:", getNilMap()) fmt.Println("Nil Channel:", getNilChannel()) fmt.Println("Nil Interface:", getNilInterface()) }

image

image

package models type LinksValueSchema struct { Href string `json:"href"` }

image


image

linksValue := models.LinksValueSchema{Href: putLink} responseBody.Links = make(map[string]models.LinksValueSchema) responseBody.Links["5g-aka"] = linksValue
  • make function doesnt need to import module.

image
image
image

//You can use this example to print the result, and see the structure. package main import ( "fmt" "models" ) func main() { // 假設 putLink 是一個有效的 URL 字串 putLink := "https://example.com/5g-aka" // 創建 LinksValueSchema 實例 linksValue := models.LinksValueSchema{Href: putLink} // 初始化 responseBody 的 Links 映射 var responseBody models.ResponseBody responseBody.Links = make(map[string]models.LinksValueSchema) // 將 linksValue 添加到映射中,鍵為 "5g-aka" responseBody.Links["5g-aka"] = linksValue // 打印結果 fmt.Println(responseBody) }

strictHex()

image

func strictHex(s string, n int) string { l := len(s) if l < n { return fmt.Sprintf(strings.Repeat("0", n-l) + s) } else { return s[l-n : l] } }

image

package main import ( "fmt" "strings" ) func strictHex(s string, n int) string { l := len(s) if l < n { return fmt.Sprintf(strings.Repeat("0", n-l) + s) } else { return s[l-n : l] } } func main() { authSubsSequenceNumber := "12345" sqnStr := strictHex(authSubsSequenceNumber, 12) fmt.Println(sqnStr) // 輸出 "0000000012345" authSubsSequenceNumber = "1234567890ABCDEF" sqnStr = strictHex(authSubsSequenceNumber, 12) fmt.Println(sqnStr) // 輸出 "7890ABCDEF" }

image

Some computation

big/SetString

image

package main import ( "fmt" "math/big" ) func main() { sqnStr := "123ABC" bigSQN := new(big.Int) bigSQN, success := bigSQN.SetString(sqnStr, 16) if !success { fmt.Println("轉換失敗") } else { fmt.Println("轉換成功:", bigSQN) } }

image

// 假設 authSubs.SequenceNumber 是一個十六進制字符串 sqnStr := "16f3b3f70ff2" bigSQN := new(big.Int) bigSQN, success := bigSQN.SetString(sqnStr, 16) if !success { logger.GmmLog.Infof("轉換失敗") return nil, fmt.Errorf("無法轉換序列號") } // 進行大數運算,例如增加序列號 bigInc := big.NewInt(1) bigSQN.Add(bigSQN, bigInc) // 將結果轉換回十六進制字符串 newSqnStr := fmt.Sprintf("%x", bigSQN) logger.GmmLog.Infof("新的序列號: %s", newSqnStr)

NewInt/Add/Mod

image
image

package main import ( "fmt" "math/big" ) func main() { // 定義常數和初始值 SqnMAx := int64(0xFFFFFFFFFFFF) sqnStr := "16f3b3f70ff2" // 將 sqnStr 轉換為大數 bigSQN := new(big.Int) bigSQN, success := bigSQN.SetString(sqnStr, 16) if !success { fmt.Println("轉換失敗") return } // 定義增量和最大值 bigInc := big.NewInt(1) bigP := big.NewInt(SqnMAx) // 增加序列號並進行模運算 bigSQN.Add(bigSQN, bigInc) bigSQN.Mod(bigSQN, bigP) // 將結果轉換回十六進制字符串 newSqnStr := fmt.Sprintf("%x", bigSQN) fmt.Println("新的序列號:", newSqnStr) }

Declaration & :=, =, ==

image

package main import "fmt" // 全域變數宣告 var globalVar int = 100 func main() { // 宣告並初始化變數 var a int = 10 var b = 20 // 類型推斷 var c int // 宣告但不初始化,默認值為 0 fmt.Println(a, b, c) fmt.Println(globalVar) }

image
image

package main import "fmt" func main() { var ( a int = 10 b string = "hello" c float64 = 3.14 ) fmt.Println(a, b, c) }

image

package main import "fmt" func main() { const pi = 3.14159 const hello = "Hello, World!" fmt.Println(pi) fmt.Println(hello) }

image

package main import "fmt" func add(a int, b int) int { return a + b } func main() { result := add(3, 4) fmt.Println(result) // 輸出: 7 }

image

package main import "fmt" func swap(a, b int) (int, int) { return b, a } func main() { x, y := swap(3, 4) fmt.Println(x, y) // 輸出: 4 3 }

image

package main import "fmt" func divide(a, b int) (result int, err error) { if b == 0 { err = fmt.Errorf("division by zero") return } result = a / b return } func main() { result, err := divide(10, 2) if err != nil { fmt.Println("Error:", err) } else { fmt.Println("Result:", result) // 輸出: Result: 5 } }

image

image

package main import "fmt" func main() { // 使用 := 進行變數宣告和賦值 a := 5 // a 是 int 型別,值為 5 b := "hello" // b 是 string 型別,值為 "hello" c := 3.14 // c 是 float64 型別,值為 3.14 // 打印變數的值 fmt.Println(a) // 輸出: 5 fmt.Println(b) // 輸出: hello fmt.Println(c) // 輸出: 3.14 }

image

package main import "fmt" func main() { // 使用 := 宣告並初始化變數 x := 10 fmt.Println(x) // 輸出: 10 // 使用 = 賦值給已宣告的變數 x = 20 fmt.Println(x) // 輸出: 20 }

image

package main import "fmt" func main() { a := 5 b := 5 c := 10 // 使用 == 比較變數的值 fmt.Println(a == b) // 輸出: true fmt.Println(a == c) // 輸出: false }

image

recover()

image

func main() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered from panic:", r) } }() mightPanic() fmt.Println("This will not be printed if panic is not recovered") } func mightPanic() { panic("Something went wrong!") }

image

package main import ( "fmt" ) func main() { safeFunction() fmt.Println("Program continues to run...") } func safeFunction() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in safeFunction:", r) } }() panicFunction() } func panicFunction() { panic("A severe error occurred!") }

image

map[string]interface {}

image

package main import ( "fmt" ) func main() { // 定義一個 map[string]interface{} data := make(map[string]interface{}) // 向 map 中添加不同類型的數據 data["name"] = "Alice" data["age"] = 30 data["isStudent"] = false data["grades"] = []int{85, 90, 92} // 訪問 map 中的數據 fmt.Println("Name:", data["name"]) fmt.Println("Age:", data["age"]) fmt.Println("Is Student:", data["isStudent"]) fmt.Println("Grades:", data["grades"]) }

image

package main import ( "encoding/json" "fmt" ) func main() { jsonString := `{ "name": "Bob", "age": 25, "isStudent": true, "grades": [88, 76, 93] }` var data map[string]interface{} // 將 JSON 字符串解析為 map[string]interface{} err := json.Unmarshal([]byte(jsonString), &data) if err != nil { fmt.Println("Error:", err) return } // 訪問解析後的數據 fmt.Println("Name:", data["name"]) fmt.Println("Age:", data["age"]) fmt.Println("Is Student:", data["isStudent"]) fmt.Println("Grades:", data["grades"]) }

image

func main() { data := map[string]interface{}{ "name": "Alice", "age": 30, "isStudent": false, "grades": []int{85, 90, 92}, } // 類型斷言 name, ok := data["name"].(string) if !ok { fmt.Println("Name is not a string") } else { fmt.Println("Name:", name) } age, ok := data["age"].(int) if !ok { fmt.Println("Age is not an int") } else { fmt.Println("Age:", age) } isStudent, ok := data["isStudent"].(bool) if !ok { fmt.Println("isStudent is not a bool") } else { fmt.Println("Is Student:", isStudent) } grades, ok := data["grades"].([]int) if !ok { fmt.Println("Grades is not a []int") } else { fmt.Println("Grades:", grades) } }

image

The reason MongoDB use this format

image

go get go.mongodb.org/mongo-driver/mongo

image

package main import ( "context" "fmt" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/bson" "log" "time" ) func main() { // 設置 MongoDB 連接選項 clientOptions := options.Client().ApplyURI("mongodb://localhost:27017") // 連接到 MongoDB client, err := mongo.Connect(context.TODO(), clientOptions) if err != nil { log.Fatal(err) } // 檢查連接是否成功 err = client.Ping(context.TODO(), nil) if err != nil { log.Fatal(err) } fmt.Println("Connected to MongoDB!") // 指定數據庫和集合 collection := client.Database("testdb").Collection("testcollection") // 查詢一個文檔 var result bson.M filter := bson.M{"name": "Alice"} err = collection.FindOne(context.TODO(), filter).Decode(&result) if err != nil { log.Fatal(err) } // 打印結果 fmt.Println("Result:", result) // 關閉連接 err = client.Disconnect(context.TODO()) if err != nil { log.Fatal(err) } fmt.Println("Connection to MongoDB closed.") }

image

// 假設 result 已經包含從 MongoDB 查詢到的數據 name, ok := result["name"].(string) if ok { fmt.Println("Name:", name) } age, ok := result["age"].(int32) if ok { fmt.Println("Age:", age) }

Why don't we access the content of this format in free5GC directly, but use structure to replace ?

image

authSubs := map[string]interface{}{ "authenticationMethod": "5G_AKA", "permanentKey": map[string]interface{}{ "permanentKeyValue": "8baf473f2f8fd09487cccbd7097c6862", "encryptionAlgorithm": "0", "encryptionKey": "0", }, "sequenceNumber": "000000000034", "authenticationManagementField": "8000", "milenage": map[string]interface{}{ "op": map[string]interface{}{ "opValue": "8e27b6af0e692e750f32667a3b14605d", "encryptionAlgorithm": "0", "encryptionKey": "0", }, "opc": map[string]interface{}{ "opcValue": "", "encryptionAlgorithm": "0", "encryptionKey": "0", }, }, "ueId": "imsi-208930000000003", }

image

// 先從 map 中取出 permanentKey permanentKey, ok := authSubs["permanentKey"].(map[string]interface{}) if !ok { // 處理錯誤,例如 permanentKey 字段不存在或類型不匹配 log.Fatalf("permanentKey not found or not a map[string]interface{}") } // 從 permanentKey 中取出 permanentKeyValue permanentKeyValue, ok := permanentKey["permanentKeyValue"].(string) if !ok { // 處理錯誤,例如 permanentKeyValue 字段不存在或類型不匹配 log.Fatalf("permanentKeyValue not found or not a string") } fmt.Println("PermanentKeyValue:", permanentKeyValue)

image

type PermanentKey struct { PermanentKeyValue string `json:"permanentKeyValue"` EncryptionAlgorithm string `json:"encryptionAlgorithm"` EncryptionKey string `json:"encryptionKey"` } type Milenage struct { Op struct { OpValue string `json:"opValue"` EncryptionAlgorithm string `json:"encryptionAlgorithm"` EncryptionKey string `json:"encryptionKey"` } `json:"op"` Opc struct { OpcValue string `json:"opcValue"` EncryptionAlgorithm string `json:"encryptionAlgorithm"` EncryptionKey string `json:"encryptionKey"` } `json:"opc"` } type AuthSubs struct { AuthenticationMethod string `json:"authenticationMethod"` PermanentKey *PermanentKey `json:"permanentKey"` SequenceNumber string `json:"sequenceNumber"` AuthenticationManagementField string `json:"authenticationManagementField"` Milenage *Milenage `json:"milenage"` UeId string `json:"ueId"` } func main() { var authSubs AuthSubs // 假設從數據庫中獲取數據並反序列化為 authSubs 結構體 // ... // 直接訪問 PermanentKeyValue 字段 fmt.Println("PermanentKeyValue:", authSubs.PermanentKey.PermanentKeyValue) }

image

int32()

image

image

package main import ( "fmt" ) type ProblemDetails struct { Status int32 Detail string // 假設有其他欄位 } func main() { // 假設 rsp 是一個 HTTP 回應物件,StatusCode 是其狀態碼 rsp := struct { StatusCode int }{ StatusCode: 404, // 假設狀態碼為 404 } var problemDetails ProblemDetails // 將 rsp.StatusCode 轉換為 int32,並賦值給 problemDetails.Status problemDetails.Status = int32(rsp.StatusCode) fmt.Printf("ProblemDetails 的狀態碼為: %d\n", problemDetails.Status) }

image

%x

image

package main import ( "fmt" ) func main() { num := 255 fmt.Printf("%x\n", num) // 輸出:ff }

image

package main import ( "fmt" ) func main() { str := "hello" fmt.Printf("%x\n", str) // 輸出:68656c6c6f }

image

package main import ( "fmt" ) func main() { data := []byte{0, 1, 2, 10, 15, 255} fmt.Printf("%x\n", data) // 輸出:0001020a0fff }

image

package main import ( "fmt" ) func main() { data := []byte{0, 1, 2, 10, 15, 255} fmt.Printf("% x\n", data) // 輸出:00 01 02 0a 0f ff }

image

package main import ( "fmt" ) func main() { num := 255 str := "hello" data := []byte{0, 1, 2, 10, 15, 255} fmt.Printf("Number in hex: %x\n", num) // Number in hex: ff fmt.Printf("String in hex: %x\n", str) // String in hex: 68656c6c6f fmt.Printf("Bytes in hex: %x\n", data) // Bytes in hex: 0001020a0fff fmt.Printf("Bytes with space: % x\n", data) // Bytes with space: 00 01 02 0a 0f ff }

Function declaration

image
image

Structure printing

image

package main import ( "fmt" ) type Person struct { Name string Age int Email string } func main() { p := Person{ Name: "Alice", Age: 30, Email: "alice@example.com", } // 使用%v打印 struct fmt.Printf("%v\n", p) // {Alice 30 alice@example.com} // 使用%+v打印 struct,包括字段名 fmt.Printf("%+v\n", p) // {Name:Alice Age:30 Email:alice@example.com} // 使用%#v打印 struct,顯示詳細信息 fmt.Printf("%#v\n", p) // main.Person{Name:"Alice", Age:30, Email:"alice@example.com"} // 使用%T打印 struct 的類型 fmt.Printf("%T\n", p) // main.Person // 打印 struct 的字段值,分別用不同格式 fmt.Printf("Name: %s, Age: %d (bin: %b, hex: %x), Email: %s\n", p.Name, p.Age, p.Age, p.Age, p.Email) }
{Alice 30 alice@example.com} {Name:Alice Age:30 Email:alice@example.com} main.Person{Name:"Alice", Age:30, Email:"alice@example.com"} main.Person Name: Alice, Age: 30 (bin: 11110, hex: 1e), Email: alice@example.com

MongoDB

  • About the explanation of Go language executing sequence -> Link

Connection

  • At first I thought these logs represent that 5GC has connected to MongoDB.
    image
    • But no, because the modification in AMF still can not connect to DB, but original UDR can, and the logs are just print after UPF start from run.sh, I dont know what it is for.
      image
  • The thing turned to my mind is that Terry manually set the connection in the init.go in AMF, which means it is necessary to do this before get the data.
    • So I go to search the name of func SetMongoDB to see where it is used, it must be in UDR but we can only find func getDataFromDB use mongoapi.RestfulAPIGetOne.
      image
    • You can see it is called here to build the connection when start UDR in init.go.
      image
      image

go.work

image
image
image
image
image
image
image
image
image
image

image
image
image
image
image

image
image
image
image

PCF context problem

go.mod replace

image
image
image
image
image
image
image
image
image


image
image
image
image
image
image
image
image


internal in golang

image
image
image

Combine two go.mod

image
image
image
image
image

go.work

image
image
image
image
image
image
image
image
image
image
image

internal bigger than go.work

image
image
image
image
image
image
image
image
image


Move outside internal

image
image
image

can not still use shared go.mod

image
image
image
image
image
image
image
image

The reason

image
image
image

The result

image
image
image
image

  • Then is the same problem so ask more detailed (The screenshots see the improvement note).
    image
    image
    image
    image
    image
    image
    image
    image
    image
    image
  • Then is to ask the method how to solve, so no take screenshots here, just see the results in improvement note.

The method of two go routine

image
image
image
image
image
image
image
image
image
image
image
image
image

OpenAPI

Use SMFPCF as example

  • Consumer means the http client, and producer means the http server in the communication between NFs
  • Sbi is the service based interface related folder, storing the api files in each NF.
    image

Architecture

Openapi(SMFPCF)

Tracing

  • How can sm_policy.go use the parameter smContext to call the function on github?
    1. First, this parameter is passed from pdu_session.go
      image
      V
      image
    2. And the parameter is declared by the function in smf_context,
      image
      which is imported from the the other package "context"
      image
    3. Let's saerch the calling function directly, we can see two context folder, but the one in smf is correct.
      image
      image
    4. Final, the func NewSMContext create a new smContext using a defined structure SMContxt, we can find the structure up there,
      image
      then when we look back to the parameter "SMPolicyClient" the sm_policy.go use,
      image
      we can find it is in the structure.
      image
    5. So the result is that "SMPolicyClient" in the structure is declared as a APIClient reference of the package "Npcf_SMPolicyControl".
      image
    6. If we see into github, we can find this function which including "DefaultApi",
      image
      image
      then the DefaultApi can call "SmPloiciesPost" (dont know how it can, maybe it can use DefaultApi to call the function in the same folder?) which call the routers.go in PCF,
      image
      image

Core modules/Network functions

AMF

Security mode

  • Procedure defined in 3GPP TS 33.501 version 15.2.0 Release 15
  • Header type defined in 3GPP TS 24.501 version 15.3.0 Release 15
  • The conclusion made by chatGPT :
    image
    image

AUSF

Authentication Server Services / ETSI TS 129 509 V16.7.0 (2021-04)
Security architecture and procedures for 5G System / ETSI TS 133 501 V15.2.0 (2018-10)

Functionalities

  • Authenticate the UE for the requester NF,
  • Provide keying material to the requester NF,
  • Protect the Steering Information List for the requester NF.
  • Protect the UE Parameter Update Data for the requester NF.

Service-based architecture

image

  • SEAF(SEcurity Anchor Function)(安全錨功能) : The function that serves in the serving network as the anchor for security in 5G, provides the authentication functionality via the AMF in the serving network. The SEAF shall support primary authentication using SUCI.
    • image
  • SEAF function is collocated(搭配) with the AMF.
  • PLMN
    • Public Land Mobile Network is hosted by government or the permitted operator, provides mobile communication technology to public.
    • PLMN=mcc+mnc.
    • Home PLMN(歸屬PLMN) : the PLMN in IMSI of the user SIM card is identical with HPLMN.
    • Visited PLMN(訪問PLMN) : The PLMN of SIM is not completely same as VPLMN.

Serving network & Home network

  • In 5G, serving network include the component which provide the service, like AMF, and home network includes the components which store the register info.
    image
    image
  • For example, if you are roaming, you will be changed to different serving network, but go to the same home network for getting your subscriber data.
    image

Provided services

  • Nausf_UEAuthentication
  • Nausf_SoRProtection
  • Nausf_UPUProtection
    image

Nausf_UEAuthentication

image
Ref

5G-AKA

image

  • UE's identifier like IMSI, SUCI(Subscription Concealed Identifier) will not be transmitted in plaintext in 5G, it's different from 4G.
  • SNN(Service Network Name) can be used for authenticaion of SEAF in AUSF
  • SIDF(Subscriber Identity De-concealing Function) can decrypt the SUCI into SUPI if AUSF provides to UDM, and the SUPI can be used for choosing the authenticating method.
  • AV : Authentication Vector

Ref

5G-AKA v.s. EAP-AKA'

  • In free5GC, AUSF will search the authentication method in UDM (Ref), UDM will check the contract content to see which method it use.
  • Normally, the authentication method is decided by the operator, which is pre-assigned to the 5GC.
  • 5G-AKA (Authentication and Key Agreement)
    • Specifically Designed for 5G.
    • Based on SIM and AuC (Authentication Center).
    • 5G-AKA is integrated into the 5G standards and is widely used as the primary authentication mechanism in 5G networks.
    • It provides robust security features to protect user identities and ensure the confidentiality and integrity of communications.
      • 5G AKA involves multiple stages, including a series of challenges and responses, to ensure secure communication between the user and the network.
  • EAP-AKA' (Extensible Authentication Protocol - AKA Prime):
    • EAP-AKA' is an extension of the Extensible Authentication Protocol (EAP) that encapsulates the AKA (Authentication and Key Agreement) protocol
      • EAP is a more general authentication protocol used not only in 5G networks but also widely in other wireless networks such as Wi-Fi.
      • In the 5GC, EAP is typically used in conjunction with EAP-AKA' (a version encapsulating 5G AKA) to provide greater flexibility and interoperability.
    • EAP-AKA' allows for compatibility with existing authentication infrastructures and protocols, making it suitable for integration into heterogeneous networks.
    • EAP requires more infrastructure support and is typically more complex than 5G AKA, but it offers greater flexibility and scalability.
      • It offers greater flexibility in authentication methods and protocols, allowing operators to leverage various authentication mechanisms beyond 5G-AKA.
      • EAP-AKA' enhances interoperability between different network types and facilitates seamless roaming across networks.

Auth parameters generating

image
image
image
image
Ref

Nausf_SoRProtection & Nausf_UPUProtection

image

  • Left is in the free5gc, right is in the AUSF services spec.
  • Until now, it dosent affect the main UEauthentication part, so I didnt do any detailed investigation on it.

NSSF

Definition

  • Ref
  • NS allows for the creation of multiple logical, isolated, and independent virtual networks that can coexist within a shared physical infrastructure.
  • Each network slice provides dedicated and customized network resources to meet the specific requirements of different services
  • The main elements of a network slice include:
    • Virtualized Network Functions (VNFs)
    • Isolation and Resource Allocation
    • Orchestration and Management

image

  • MANO is a NFV based architecture.
    image
  • MANO 5GC

Network Slicing Identifier

  • Ref
  • NSSAI (Network Slice Selection Assistance Information) is a set of S-NSSAI, can be classified into 5.
    image
  • The deifnition in 5GC.
    image
  • The NFs join the NS function, and the NSSAI they have. (From On the Rollout of Network Slicing in Carrier Networks: A Technology Radar)
    image
  • From the release of 3GPP R15, the NS is mentioned, and it needs the support from not only NG-RAN but also CN, so 5G system use S-NSSAI(Single-NSSAI) and NSSAI to do slice management.
  • S-NSSAI is combined from two fields.
    • SST (Slice/Service Type) : Different SST implies different applied scene, like 1 for eMBB, 2 for uRLLC, 3 for mIoT, 4 for V2V and 5 for HMTC(High-Performance Machine-Type Communications).
    • SD (Slice Differentiator) : Subdivide functions in the same scenario, including mobile network or fixed wireless access network, charging, slice priority, tenancy.

Info in SPEC

Nnssf_NSSelection

  • Ref
  • Comsumer in other PLMN (AMF, NSSF) search (GET) the info about network slice in roaming or not in roaming.
    • Comsumer find NSSF based on local configuration, or find NSSF in different PLMN based on its own FQDN.
  • NSSF use it to provide Allowed NSSAI and Configured NSSAI of served PLMN to AMF.
  • Applied Scenes
    image
  • image
    image
    image

Nnssf_NSSAIAvailability

  • Comsumer (AMF) update the Supported S-NSSAI on every Tracking Area of NSSF
  • Subscribe or unsubscribe the change notification of
    • NSSAI Availability info on each TA.
    • Resricted S-NSSAI in every PLMN in the TA of UE served PLMN.

image

Info from Terry

  • There are some slicing method, one is using multiple UPF, one is using one UPF only.
  • The test ref from Terry : Link
    • Ther conclusion for this test is that we can not see the influence of slice seperate by using only one UPF, because different UE can ping each other in different slice.
    • UPF is like a router, can assign different sub-domain and set the router to make them able to communication with each other.

UCLC

image

PCF

Study from our content

  • The code tracing I done before : Link
    • The AMF policy part is useless because it is all about commenting out the error, but didnt solve the panic error.
    • The SMF part may be useful, because there are some record of the process of SMF policy creating.
  • Note from Rifqi : Link
    • Thers are some info from SPEC, and his own code tracing, but it is not finished.

Study on SPEC/Background

BSF

  • The function related to PCF.

UDM/UDR

UDM

  • Authentication part has been introduced in AUSF.
  • Here just introduces some SDM functions which will be part of the modification in UDM/UDR.

UeCmRegistration

image

SdmSubscriptions

image

UDR

  • You can see it as an API between NFs and MongoDB.
    • UDM (AUSF) will call it to manage UE auth info.
    • PCF will call it to manage policy data.
    • AMF will do SDM by calling UDM to call it.
    • SMF will get context from UDM calling it.

SMF

IP allocation

Ref
Ref

  • I think the IP allocation in CN has many probability, from SMF, UPF, or the DHCP server outside, but in usual E2E test with UERANSIM is from SMF.
    unnamed

Protocols

NGAP

Lightweight core

Before & After

Module

image
image
image

Call flow

  • Original
    image
    image
    image
    image
  • Lightweight
    image
    image
    image
    image

Fix the parameter

Authen. context

Remove AUSF

What happen?

How to repair?

Remove NSSF

Remove PCF

Select a repo