Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package libnas
- import (
- "encoding/binary"
- "errors"
- "fmt"
- "log"
- "reflect"
- "strconv"
- )
- // TNasMsg
- // all implementations should be a pointer to type
- type TNasMsg interface {
- Unmarshal(pdu []byte) (res TNasMsg, err error)
- }
- type TNasMsgIE interface {
- Value() []byte
- Set(any)
- }
- func (pdu *TNAS) UnmarshalNasPdu() (res TNasMsg, err error) {
- t, err := pdu.Type()
- if err != nil {
- return
- }
- switch pdu.PD() {
- case PROTOCOL_DISCRIMINATOR_EPS_MOBILITY_MANAGEMENT_MESSAGES:
- switch t {
- case NAS_EMM_MESSAGE_TYPE_ATTACH_ACCEPT:
- return (&TEmmAttachAccept{}).Unmarshal(pdu.decodedMsg.msg)
- case NAS_EMM_MESSAGE_TYPE_ATTACH_REQUEST:
- return (&TEmmAttachRequest{}).Unmarshal(pdu.decodedMsg.msg)
- case NAS_EMM_MESSAGE_TYPE_SECURITY_MODE_COMMAND:
- return (&TEmmSecurityModeCommand{}).Unmarshal(pdu.decodedMsg.msg)
- case NAS_EMM_MESSAGE_TYPE_SECURITY_MODE_COMPLETE:
- return (&tEmmSecurityModeComplete{}).Unmarshal(pdu.decodedMsg.msg)
- case NAS_EMM_MESSAGE_TYPE_AUTHENTICATION_RESPONSE:
- return (&TEmmAuthenticationResponse{}).Unmarshal(pdu.decodedMsg.msg)
- default:
- return nil, errors.New("not supported")
- }
- case PROTOCOL_DISCRIMINATOR_EPS_SESSION_MANAGEMENT_MESSAGES:
- switch t {
- case NAS_ESM_MESSAGE_TYPE_ESM_INFORMATION_RESPONSE:
- return (&TEsmInformationResponse{}).Unmarshal(pdu.decodedMsg.msg)
- case NAS_ESM_MESSAGE_TYPE_ESM_INFORMATION_REQUEST:
- return (&TEsmInformationRequest{}).Unmarshal(pdu.decodedMsg.msg)
- case NAS_ESM_MESSAGE_TYPE_PDN_CONNECTIVITY_REQUEST:
- return (&TEsmPdnConnectivityRequest{}).Unmarshal(pdu.decodedMsg.msg)
- case NAS_ESM_MESSAGE_TYPE_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST:
- return (&TEsmActivateDefaultEpsBearerContextRequest{}).Unmarshal(pdu.decodedMsg.msg)
- default:
- return nil, errors.New("not supported")
- }
- default:
- return nil, errors.New("not supported")
- }
- }
- func MarshalNasPdu(msg TNasMsg) (res []byte, err error) {
- sMsg := reflect.ValueOf(msg)
- tMsg := sMsg.Type()
- if tMsg.Kind() == reflect.Pointer {
- tMsg = tMsg.Elem()
- sMsg = reflect.ValueOf(msg).Elem()
- }
- for i := 0; i < sMsg.NumField(); i++ {
- ieV := sMsg.Field(i)
- var complVal bool
- if ieV.Type().Implements(reflect.TypeOf((*TNasMsgIE)(nil)).Elem()) {
- ieV = ieV.MethodByName("Value").Call([]reflect.Value{})[0]
- complVal = true
- } else if ieV.CanAddr() && ieV.Addr().Type().Implements(reflect.TypeOf((*TNasMsgIE)(nil)).Elem()) {
- ieV = ieV.Addr().MethodByName("Value").Call([]reflect.Value{})[0]
- complVal = true
- }
- var vRes []byte
- ieT := tMsg.Field(i).Tag.Get("nas_ie_type")
- switch ieT {
- case "V":
- ieL := tMsg.Field(i).Tag.Get("nas_ie_length")
- if ieL == "1/2" {
- ieP := tMsg.Field(i).Tag.Get("nas_ie_position")
- if ieP == "LSB" {
- vRes = []byte{byte(ieV.Uint())}
- } else if ieP == "MSB" {
- // todo implement here complex types
- res[len(res)-1] = (res[len(res)-1] & 0x0f) | byte(ieV.Uint()<<4)
- continue
- }
- } else {
- var l int
- l, err = strconv.Atoi(ieL)
- if err != nil {
- return nil, err
- }
- vRes = make([]byte, l)
- if l == 1 {
- vRes[0] = byte(ieV.Uint())
- } else {
- copy(vRes, ieV.Bytes()[:l])
- }
- }
- case "LV":
- l := byte(len(ieV.Bytes()))
- vRes = append(vRes, l)
- vRes = append(vRes, ieV.Bytes()...)
- case "LVE":
- l := uint16(len(ieV.Bytes()))
- la := make([]byte, 2)
- _, _ = binary.Encode(la, binary.BigEndian, l)
- vRes = append(vRes, la...)
- vRes = append(vRes, ieV.Bytes()...)
- case "T":
- if ieV.IsNil() {
- continue
- }
- var iei int64
- iei, err = strconv.ParseInt(tMsg.Field(i).Tag.Get("nas_iei"), 0, 8)
- if err != nil {
- return nil, err
- }
- vRes = append(vRes, byte(iei))
- case "TV":
- if ieV.IsNil() {
- continue
- }
- ieL := tMsg.Field(i).Tag.Get("nas_ie_length")
- var l int
- l, err = strconv.Atoi(ieL)
- if err != nil {
- return nil, err
- }
- var iei int64
- iei, err = strconv.ParseInt(tMsg.Field(i).Tag.Get("nas_iei"), 0, 8)
- if err != nil {
- return nil, err
- }
- var _ieV reflect.Value
- if complVal {
- _ieV = ieV
- } else {
- _ieV = ieV.Elem()
- }
- if l == 1 {
- vRes = append(vRes, _ieV.Bytes()[0]|byte(iei)<<4)
- } else {
- l-- // skip ie identifier - it is one byte always
- vRes = append(vRes, byte(iei))
- vRes = append(vRes, _ieV.Bytes()[:l]...)
- }
- case "TLV":
- if ieV.IsNil() {
- continue
- }
- var iei int64
- iei, err = strconv.ParseInt(tMsg.Field(i).Tag.Get("nas_iei"), 0, 8)
- if err != nil {
- return nil, err
- }
- var _ieV reflect.Value
- if complVal {
- _ieV = ieV
- } else {
- _ieV = ieV.Elem()
- }
- l := byte(len(_ieV.Bytes()))
- vRes = append(vRes, byte(iei))
- vRes = append(vRes, l)
- vRes = append(vRes, _ieV.Bytes()[:l]...)
- case "TLVE":
- if ieV.IsNil() {
- continue
- }
- var iei int64
- iei, err = strconv.ParseInt(tMsg.Field(i).Tag.Get("nas_iei"), 0, 8)
- if err != nil {
- return nil, err
- }
- var _ieV reflect.Value
- if complVal {
- _ieV = ieV
- } else {
- _ieV = ieV.Elem()
- }
- l := uint16(len(_ieV.Bytes()))
- la := make([]byte, 2)
- _, _ = binary.Encode(la, binary.BigEndian, l)
- vRes = append(vRes, byte(iei))
- vRes = append(vRes, la...)
- vRes = append(vRes, _ieV.Bytes()[:l]...)
- }
- if vRes != nil {
- res = append(res, vRes...)
- }
- }
- return
- }
- func unmarshalNasPdu(pdu []byte, t reflect.Type) (res TNasMsg, err error) {
- if t.Kind() != reflect.Struct {
- return nil, errors.New("can unmarshal only to struct")
- }
- sRes := reflect.New(t)
- sMsg := sRes.Elem()
- tMsg := sMsg.Type()
- var pPos, tFieldsStart int
- mandatoryFields:
- for i := 0; i < sMsg.NumField(); i++ {
- ieT, ok := tMsg.Field(i).Tag.Lookup("nas_ie_type")
- if !ok { // skip untagged fields of message struct
- continue
- }
- var val reflect.Value
- switch ieT {
- case "V":
- ieL := tMsg.Field(i).Tag.Get("nas_ie_length")
- if ieL == "1/2" {
- a := uint8(0)
- val = reflect.ValueOf(&a).Elem()
- if tMsg.Field(i).Tag.Get("nas_ie_position") == "LSB" {
- val.SetUint(uint64(pdu[pPos] & 0xf))
- } else if tMsg.Field(i).Tag.Get("nas_ie_position") == "MSB" {
- val.SetUint(uint64(pdu[pPos] >> 4))
- pPos++
- } else {
- return nil, errors.New(fmt.Sprintf("nas_ie_position must be LSB or MSB but %s found",
- tMsg.Field(i).Tag.Get("nas_ie_position")))
- }
- } else if ieL == "1" {
- a := uint8(0)
- val = reflect.ValueOf(&a).Elem()
- if val.Kind() != reflect.Uint8 {
- return nil, errors.New(fmt.Sprintf("field with nas_ie_type V and length 1/2 can "+
- "have only byte/Uint8 kind, but %s found", val.Kind()))
- }
- val.SetUint(uint64(pdu[pPos]))
- pPos++
- } else {
- l, err := strconv.Atoi(ieL)
- if err != nil {
- return nil, err
- }
- a := make([]byte, l)
- val = reflect.ValueOf(&a).Elem()
- if val.Kind() != reflect.Slice {
- return nil, errors.New(fmt.Sprintf("field with nas_ie_type V and length more then 1 "+
- "can be only slice, but %s found", val.Kind()))
- }
- val.SetBytes(pdu[pPos : pPos+l])
- pPos += l
- }
- case "LV":
- l := int(pdu[pPos])
- pPos++
- a := make([]byte, l)
- val = reflect.ValueOf(&a).Elem()
- if val.Kind() != reflect.Slice {
- return nil, errors.New(fmt.Sprintf("field with nas_ie_type LV "+
- "can be only slice, but %s found", val.Kind()))
- }
- val.SetBytes(pdu[pPos : pPos+l])
- pPos += l
- case "LVE":
- var l uint16
- _, err = binary.Decode(pdu[pPos:pPos+2], binary.BigEndian, &l)
- if err != nil {
- return nil, err
- }
- pPos += 2
- a := make([]byte, l)
- val = reflect.ValueOf(&a).Elem()
- if val.Kind() != reflect.Slice {
- return nil, errors.New(fmt.Sprintf("field with nas_ie_type LVE "+
- "can be only slice, but %s found", val.Kind()))
- }
- val.SetBytes(pdu[pPos : pPos+int(l)])
- pPos += int(l)
- default:
- tFieldsStart = i
- break mandatoryFields
- }
- if sMsg.Field(i).Type().Implements(reflect.TypeOf((*TNasMsgIE)(nil)).Elem()) {
- sMsg.Field(i).MethodByName("Set").Call([]reflect.Value{val})
- } else if sMsg.Field(i).CanAddr() && sMsg.Field(i).Addr().Type().Implements(reflect.TypeOf((*TNasMsgIE)(nil)).Elem()) {
- sMsg.Field(i).Addr().MethodByName("Set").Call([]reflect.Value{val})
- } else {
- sMsg.Field(i).Set(val.Convert(sMsg.Field(i).Type()))
- }
- }
- for pPos < len(pdu) {
- var idx int
- idx, err = getFieldIdxByIEI(sMsg, pdu[pPos], tFieldsStart)
- if errors.Is(err, ENASUnknownIEI{}) {
- log.Print(err)
- err = nil
- if pdu[pPos]&0b10000000 == 0b10000000 {
- pPos++
- continue
- } else if pdu[pPos]&0b01111000 == 0b01111000 {
- var l uint16
- _, _ = binary.Decode(pdu[pPos+1:pPos+3], binary.BigEndian, &l)
- pPos += 3 + int(l)
- continue
- } else {
- l := pdu[pPos+1]
- pPos += 2 + int(l)
- continue
- }
- } else if err != nil {
- return nil, err
- }
- if sMsg.Field(idx).Type().Kind() != reflect.Pointer {
- return nil, errors.New(fmt.Sprintf("field with nas_ie_type T... should be pointer but "+
- "%s found", sMsg.Field(idx).Type().Kind()))
- }
- var sVal []byte
- switch tMsg.Field(idx).Tag.Get("nas_ie_type") {
- case "T":
- val := reflect.New(sMsg.Field(idx).Elem().Type()).Elem()
- if val.Kind() != reflect.Bool {
- return nil, errors.New(fmt.Sprintf("field with nas_ie_type T should be *bool, but *%s found",
- val.Kind()))
- }
- val.SetBool(true)
- sMsg.Field(idx).Elem().Set(val)
- pPos++
- continue
- case "TV":
- if sMsg.Field(idx).Type().Elem().Kind() != reflect.Slice {
- return nil, errors.New(fmt.Sprintf("field with nas_ie_type TV and length >1 should be "+
- "*slice, but *%s found", sMsg.Field(idx).Type().Elem().Kind()))
- }
- ieL := tMsg.Field(idx).Tag.Get("nas_ie_length")
- var l int
- l, err = strconv.Atoi(ieL)
- if err != nil {
- return nil, err
- }
- if l > 1 {
- sVal = pdu[pPos+1 : pPos+l]
- } else {
- sVal = pdu[pPos : pPos+1]
- sVal[0] &= 0x0f
- }
- pPos += l
- case "TLV":
- if sMsg.Field(idx).Type().Elem().Kind() != reflect.Slice {
- return nil, errors.New(fmt.Sprintf("field with nas_ie_type TV and length >1 should be "+
- "*slice, but *%s found", sMsg.Field(idx).Type().Elem().Kind()))
- }
- l := int(pdu[pPos+1])
- sVal = pdu[pPos+2 : pPos+2+l]
- pPos += 2 + l
- case "TLVE":
- if sMsg.Field(idx).Type().Elem().Kind() != reflect.Slice {
- return nil, errors.New(fmt.Sprintf("field with nas_ie_type TV and length >1 should be "+
- "*slice, but *%s found", sMsg.Field(idx).Type().Elem().Kind()))
- }
- var l uint16
- _, err = binary.Decode(pdu[pPos+1:pPos+3], binary.BigEndian, &l)
- if err != nil {
- return nil, err
- }
- sVal = pdu[pPos+3 : pPos+3+int(l)]
- pPos += 3 + int(l)
- }
- if tMsg.Field(idx).Type.Implements(reflect.TypeOf((*TNasMsgIE)(nil)).Elem()) {
- val := reflect.New(sMsg.Field(idx).Type().Elem())
- val.MethodByName("Set").Call([]reflect.Value{reflect.ValueOf(sVal)})
- sMsg.Field(idx).Set(val)
- } else {
- sMsg.Field(idx).Set(reflect.ValueOf(&sVal))
- }
- }
- pRes := reflect.ValueOf(&res)
- pRes.Elem().Set(sRes)
- return res, nil
- }
- func getFieldIdxByIEI(sMsg reflect.Value, iei byte, startIdx int) (res int, err error) {
- tMsg := sMsg.Type()
- for i := startIdx; i < sMsg.NumField(); i++ {
- tag := tMsg.Field(i).Tag.Get("nas_iei")
- if tag == "" {
- continue
- }
- var fIei int64
- fIei, err = strconv.ParseInt(tag, 0, 8)
- if err != nil {
- return
- }
- if byte(fIei) == iei || byte(fIei) == iei>>4 {
- return i, nil
- }
- }
- return res, NewENASUnknownIEI(iei)
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement