Properly parses most message types
This commit is contained in:
		
							
								
								
									
										226
									
								
								sdb.go
									
									
									
									
									
								
							
							
						
						
									
										226
									
								
								sdb.go
									
									
									
									
									
								
							@ -1,22 +1,22 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IridiumSDB struct {
 | 
			
		||||
	ProtocolRevision byte
 | 
			
		||||
	MessageLength uint16
 | 
			
		||||
	Message MOMessage
 | 
			
		||||
	Length           uint16
 | 
			
		||||
	Elements         []interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MOMessage struct {
 | 
			
		||||
	HeaderIEI byte
 | 
			
		||||
	HeaderLength uint16
 | 
			
		||||
type MOHeader struct {
 | 
			
		||||
	IEI          byte
 | 
			
		||||
	Length       uint16
 | 
			
		||||
	CDRReference uint32
 | 
			
		||||
	IMEI         [15]byte
 | 
			
		||||
	Status       byte
 | 
			
		||||
@ -25,52 +25,192 @@ type MOMessage struct {
 | 
			
		||||
	SessionTime  uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var SessionStatusString = []string{
 | 
			
		||||
	"The SBD session completed successfully.",
 | 
			
		||||
	"The MO message transfer, if any, was successful. The MT message queued at the Iridium Gateway is too large to be transferred within a single SBD session.",
 | 
			
		||||
	"The MO message transfer, if any, was successful. The reported location was determined to be of unacceptable quality. This value is only applicable to IMEIs using SBD protocol revision 1.",
 | 
			
		||||
	"", // 3
 | 
			
		||||
	"", // 4
 | 
			
		||||
	"", // 5
 | 
			
		||||
	"", // 6
 | 
			
		||||
	"", // 7
 | 
			
		||||
	"", // 8
 | 
			
		||||
	"", // 9
 | 
			
		||||
	"The SBD session timed out before session completion.",
 | 
			
		||||
	"", // 11
 | 
			
		||||
	"The MO message being transferred by the IMEI is too large to be transferred within a single SBD session.",
 | 
			
		||||
	"An RF link loss occurred during the SBD session.",
 | 
			
		||||
	"An IMEI protocol anomaly occurred during SBD session.",
 | 
			
		||||
	"The IMEI is prohibited from accessing the Iridium Gateway."}
 | 
			
		||||
func (h MOHeader) StatusString() string {
 | 
			
		||||
	switch h.Status {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return "The SBD session completed successfully."
 | 
			
		||||
	case 1:
 | 
			
		||||
		return "The MO message transfer, if any, was successful. The MT message queued at the Iridium Gateway is too large to be transferred within a single SBD session."
 | 
			
		||||
	case 2:
 | 
			
		||||
		return "The MO message transfer, if any, was successful. The reported location was determined to be of unacceptable quality. This value is only applicable to IMEIs using SBD protocol revision 1."
 | 
			
		||||
	case 10:
 | 
			
		||||
		return "The SBD session timed out before session completion."
 | 
			
		||||
	case 12:
 | 
			
		||||
		return "The MO message being transferred by the IMEI is too large to be transferred within a single SBD session."
 | 
			
		||||
	case 13:
 | 
			
		||||
		return "An RF link loss occurred during the SBD session."
 | 
			
		||||
	case 14:
 | 
			
		||||
		return "An IMEI protocol anomaly occurred during SBD session."
 | 
			
		||||
	case 15:
 | 
			
		||||
		return "The IMEI is prohibited from accessing the Iridium Gateway."
 | 
			
		||||
	default:
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MOPayload struct {
 | 
			
		||||
	IEI     byte
 | 
			
		||||
	Length  uint16
 | 
			
		||||
	Payload []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MOLocation struct {
 | 
			
		||||
	IEI               byte
 | 
			
		||||
	Length            uint16
 | 
			
		||||
	LocationFlags     byte
 | 
			
		||||
	LatitudeDegrees   uint8
 | 
			
		||||
	LatitudeTHMinute  uint16
 | 
			
		||||
	LongitudeDegrees  uint8
 | 
			
		||||
	LongitudeTHMinute uint16
 | 
			
		||||
	CEPRadius         uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MOConfirmation struct {
 | 
			
		||||
	IEI    byte
 | 
			
		||||
	Length uint16
 | 
			
		||||
	Status byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	if len(os.Args) < 2 {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "required argument missing\n")
 | 
			
		||||
		fmt.Fprintf(os.Stderr,
 | 
			
		||||
			"required argument missing\n")
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rdt, err := ioutil.ReadFile(os.Args[1])
 | 
			
		||||
	raw, err := ioutil.ReadFile(os.Args[1])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "error reading %s: %s\n", os.Args[1], err.Error())
 | 
			
		||||
    os.Exit(1)
 | 
			
		||||
		fmt.Fprintf(os.Stderr,
 | 
			
		||||
			"error reading \"%s\": %s\n",
 | 
			
		||||
			os.Args[1], err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	header := IridiumSDB{}
 | 
			
		||||
	buf := bytes.NewBuffer(rdt)
 | 
			
		||||
	err = binary.Read(buf, binary.BigEndian, &header)
 | 
			
		||||
	err = parseSDB(raw)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "error parsing %s: %s\n", os.Args[1], err.Error())
 | 
			
		||||
		fmt.Fprintf(os.Stderr,
 | 
			
		||||
			"%s\n", err.Error())
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "Protocol Revision: %d\n", header.ProtocolRevision)
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "Message Length: %d\n", header.MessageLength)
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "MO Header IEI: %x\n", header.Message.HeaderIEI)
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "MO Header Length: %d\n", header.Message.HeaderLength)
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "CDR Reference: %d\n", header.Message.CDRReference)
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "IMEI: %s\n", string(header.Message.IMEI[:]))
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "Status: %s (%d)\n", SessionStatusString[header.Message.Status], header.Message.Status)
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "MOMSN: %d\n", header.Message.MOMSN)
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "MTMSN: %d\n", header.Message.MTMSN)
 | 
			
		||||
	fmt.Fprintf(os.Stdout, "Session Time: %d\n", header.Message.SessionTime)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseSDB(raw []byte) error {
 | 
			
		||||
	raw_len := len(raw)
 | 
			
		||||
	if raw_len < 3 {
 | 
			
		||||
		return fmt.Errorf("message structure too short: %d bytes",
 | 
			
		||||
			len(raw))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sdb := IridiumSDB{}
 | 
			
		||||
	sdb.ProtocolRevision = raw[0]
 | 
			
		||||
	sdb.Length = binary.BigEndian.Uint16(raw[1:3])
 | 
			
		||||
 | 
			
		||||
	if (int(sdb.Length) + 3) != raw_len {
 | 
			
		||||
		return fmt.Errorf("invalid message length (expected %d, got %d)",
 | 
			
		||||
			(sdb.Length + 3), raw_len)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 3; i < raw_len; {
 | 
			
		||||
		if (i + 3) > raw_len {
 | 
			
		||||
			return fmt.Errorf("invalid element length (at %d)",
 | 
			
		||||
				i)
 | 
			
		||||
		}
 | 
			
		||||
		el_iei := raw[i]
 | 
			
		||||
		el_len := binary.BigEndian.Uint16(raw[i+1 : i+3])
 | 
			
		||||
 | 
			
		||||
		if (i + 3 + int(el_len)) > raw_len {
 | 
			
		||||
			return fmt.Errorf("invalid element length (at %d): %d",
 | 
			
		||||
				i+1, el_len)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch el_iei {
 | 
			
		||||
		// MO Header IEI
 | 
			
		||||
		case 1:
 | 
			
		||||
			buf := bytes.NewReader(raw[i : i+3+int(el_len)])
 | 
			
		||||
			moheader := MOHeader{}
 | 
			
		||||
			err := binary.Read(buf, binary.BigEndian, &moheader)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("error reading MO header (at %d): %s",
 | 
			
		||||
					i, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			sdb.Elements = append(sdb.Elements, moheader)
 | 
			
		||||
 | 
			
		||||
		// MO Payload IEI
 | 
			
		||||
		case 2:
 | 
			
		||||
			mopayload := MOPayload{}
 | 
			
		||||
			mopayload.IEI = el_iei
 | 
			
		||||
			mopayload.Length = el_len
 | 
			
		||||
			mopayload.Payload = raw[i+3 : i+3+int(el_len)]
 | 
			
		||||
			sdb.Elements = append(sdb.Elements, mopayload)
 | 
			
		||||
 | 
			
		||||
		// MO Location IEI
 | 
			
		||||
		case 3:
 | 
			
		||||
			buf := bytes.NewReader(raw[i : i+3+int(el_len)])
 | 
			
		||||
			molocation := MOLocation{}
 | 
			
		||||
			err := binary.Read(buf, binary.BigEndian, &molocation)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("error reading MO location (at %d): %s",
 | 
			
		||||
					i, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			sdb.Elements = append(sdb.Elements, molocation)
 | 
			
		||||
 | 
			
		||||
		// MO Confirmation IEI
 | 
			
		||||
		case 5:
 | 
			
		||||
			moconfirmation := MOConfirmation{}
 | 
			
		||||
			moconfirmation.IEI = el_iei
 | 
			
		||||
			moconfirmation.Length = el_len
 | 
			
		||||
			moconfirmation.Status = raw[i+3]
 | 
			
		||||
			sdb.Elements = append(sdb.Elements, moconfirmation)
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return fmt.Errorf("invalid element IEI (at %d): %d",
 | 
			
		||||
				i, el_iei)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		i += (3 + int(el_len))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Printf("Protocol Revision: %d\n",
 | 
			
		||||
		sdb.ProtocolRevision)
 | 
			
		||||
	fmt.Printf("Message Length: %d\n",
 | 
			
		||||
		sdb.Length)
 | 
			
		||||
	for c, i := range sdb.Elements {
 | 
			
		||||
		if c > 0 {
 | 
			
		||||
			fmt.Println()
 | 
			
		||||
		}
 | 
			
		||||
		switch v := i.(type) {
 | 
			
		||||
		case MOHeader:
 | 
			
		||||
			fmt.Printf("\tMO Header IEI: %d\n",
 | 
			
		||||
				v.IEI)
 | 
			
		||||
			fmt.Printf("\tMO Header Length: %d\n",
 | 
			
		||||
				v.Length)
 | 
			
		||||
			fmt.Printf("\tMO Header CDR Reference: %d\n",
 | 
			
		||||
				v.CDRReference)
 | 
			
		||||
			fmt.Printf("\tMO Header IMEI: %s\n",
 | 
			
		||||
				v.IMEI)
 | 
			
		||||
			fmt.Printf("\tMO Header Status: %s (%d)\n",
 | 
			
		||||
				v.StatusString(), v.Status)
 | 
			
		||||
			fmt.Printf("\tMO Header MOMSN: %d\n",
 | 
			
		||||
				v.MOMSN)
 | 
			
		||||
			fmt.Printf("\tMO Header MTMSN: %d\n",
 | 
			
		||||
				v.MTMSN)
 | 
			
		||||
			fmt.Printf("\tMO Header Session Time: %d\n",
 | 
			
		||||
				v.SessionTime)
 | 
			
		||||
 | 
			
		||||
		case MOPayload:
 | 
			
		||||
			fmt.Printf("\tMO Payload IEI: %d\n",
 | 
			
		||||
				v.IEI)
 | 
			
		||||
			fmt.Printf("\tMO Payload Length: %d\n",
 | 
			
		||||
				v.Length)
 | 
			
		||||
 | 
			
		||||
		case MOConfirmation:
 | 
			
		||||
			fmt.Printf("\tMO Confirmation IEI: %d\n",
 | 
			
		||||
				v.IEI)
 | 
			
		||||
			fmt.Printf("\tMO Confirmation Length: %d\n",
 | 
			
		||||
				v.Length)
 | 
			
		||||
			fmt.Printf("\tMO Confirmation Status: %d\n",
 | 
			
		||||
				v.Status)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user