|
|
|
@ -10,270 +10,16 @@ import (
|
|
|
|
|
|
|
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
|
|
|
|
|
|
"github.com/google/gopacket"
|
|
|
|
|
"github.com/google/gopacket/pcap"
|
|
|
|
|
"github.com/gordonklaus/portaudio"
|
|
|
|
|
"github.com/tehmaze/go-dmr/bit"
|
|
|
|
|
"github.com/tehmaze/go-dmr/dmr"
|
|
|
|
|
"github.com/tehmaze/go-dmr/dmr/repeater"
|
|
|
|
|
"github.com/tehmaze/go-dmr/homebrew"
|
|
|
|
|
"github.com/tehmaze/go-dmr/ipsc"
|
|
|
|
|
"github.com/tehmaze/go-dsd"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
bursttypes = map[uint32]string{
|
|
|
|
|
0: "pi header",
|
|
|
|
|
1: "voice lc header",
|
|
|
|
|
2: "terminator with lc",
|
|
|
|
|
3: "csbk",
|
|
|
|
|
4: "csbk",
|
|
|
|
|
5: "appended mbc",
|
|
|
|
|
6: "data header",
|
|
|
|
|
7: "rate ½ data continuation",
|
|
|
|
|
8: "rate ¾ data continuation",
|
|
|
|
|
9: "idle",
|
|
|
|
|
}
|
|
|
|
|
headertypes = []string{
|
|
|
|
|
"UDT ", "Resp", "UDat", "CDat", "Hdr4", "Hdr5", "Hdr6", "Hdr7",
|
|
|
|
|
"Hdr8", "Hdr9", "Hdr10", "Hdr11", "Hdr12", "DSDa", "RSDa", "Prop",
|
|
|
|
|
}
|
|
|
|
|
saptypes = []string{
|
|
|
|
|
"UDT", "1", "TCP HC", "UDP HC", "IP Pkt", "ARP Pkt", "6", "7",
|
|
|
|
|
"8", "Prop Pkt", "Short Data", "11", "12", "13", "14", "15",
|
|
|
|
|
}
|
|
|
|
|
fidMap = [256]byte{
|
|
|
|
|
0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x04, 0x05,
|
|
|
|
|
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x07, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
|
}
|
|
|
|
|
fidName = map[uint8]string{
|
|
|
|
|
0: "Unknown",
|
|
|
|
|
1: "Standard",
|
|
|
|
|
2: "Flyde Micro",
|
|
|
|
|
3: "PROD-EL SPA",
|
|
|
|
|
4: "Motorola Connect+",
|
|
|
|
|
5: "RADIODATA GmbH",
|
|
|
|
|
6: "Hyteria (8)",
|
|
|
|
|
7: "Motorola Capacity+",
|
|
|
|
|
8: "EMC S.p.A (19)",
|
|
|
|
|
9: "EMC S.p.A (28)",
|
|
|
|
|
10: "Radio Activity Srl (51)",
|
|
|
|
|
11: "Radio Activity Srl (60)",
|
|
|
|
|
12: "Tait Electronics",
|
|
|
|
|
13: "Hyteria (104)",
|
|
|
|
|
14: "Vertex Standard",
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func dumpFCLO(payload []byte, fid uint8) {
|
|
|
|
|
fmt.Printf(" fid: %s (%d)\n", fidName[fid], fid)
|
|
|
|
|
if fid == 0 || fid == 16 { // MotoTRBO Capacity+
|
|
|
|
|
fmt.Printf(" fclo: -\n")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dumpDataHeader(header []byte) {
|
|
|
|
|
dh, err := dmr.ParseDataHeader(header, false)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf(" data header error: %v\n", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
dc := dh.CommonHeader()
|
|
|
|
|
fmt.Printf(" service accesspt: %d\n", dc.ServiceAccessPoint)
|
|
|
|
|
fmt.Printf(" src id -> dst id: %d -> %d\n", dc.SrcID, dc.DstID)
|
|
|
|
|
switch d := dh.(type) {
|
|
|
|
|
case dmr.UDTDataHeader:
|
|
|
|
|
fmt.Printf(" format..........: %s (%#02x)\n", dmr.UDTFormatName[d.Format], d.Format)
|
|
|
|
|
fmt.Printf(" pad nibble......: %d\n", d.PadNibble)
|
|
|
|
|
fmt.Printf(" appended blocks.: %d\n", d.AppendedBlocks)
|
|
|
|
|
fmt.Printf(" supplementary f.: %b\n", d.SupplementaryFlag)
|
|
|
|
|
fmt.Printf(" opcode..........: %d\n", d.OPCode)
|
|
|
|
|
case dmr.UnconfirmedDataHeader:
|
|
|
|
|
fmt.Printf(" pad octet count.: %d\n", d.PadOctetCount)
|
|
|
|
|
fmt.Printf(" full message....: %b\n", d.FullMessage)
|
|
|
|
|
fmt.Printf(" blocks to follow: %d\n", d.BlocksToFollow)
|
|
|
|
|
fmt.Printf(" fragment seq.no.: %d\n", d.FragmentSequenceNumber)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dumpData(data bit.Bits) {
|
|
|
|
|
var out = make([][]byte, 7)
|
|
|
|
|
for y := 0; y < 7; y++ {
|
|
|
|
|
out[y] = make([]byte, 80)
|
|
|
|
|
for x := 0; x < 80; x++ {
|
|
|
|
|
if x == 0 || x == 18 || x == 21 || x == 30 || x == 33 || x == 51 {
|
|
|
|
|
out[y][x] = '|'
|
|
|
|
|
} else {
|
|
|
|
|
out[y][x] = ' '
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Info first half
|
|
|
|
|
for i := 0; i < 98; i++ {
|
|
|
|
|
var x = 1 + (i % 16)
|
|
|
|
|
var y = (i / 16)
|
|
|
|
|
if x > 8 {
|
|
|
|
|
x++
|
|
|
|
|
}
|
|
|
|
|
if data[i] > 0 {
|
|
|
|
|
out[y][x] = '1'
|
|
|
|
|
} else {
|
|
|
|
|
out[y][x] = '0'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Slot type first half
|
|
|
|
|
for i := 98; i < 108; i++ {
|
|
|
|
|
var x = 19 + ((i - 98) % 2)
|
|
|
|
|
var y = (i - 98) / 2
|
|
|
|
|
if data[i] > 0 {
|
|
|
|
|
out[y][x] = '1'
|
|
|
|
|
} else {
|
|
|
|
|
out[y][x] = '0'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// SYNC
|
|
|
|
|
for i := 108; i < 156; i++ {
|
|
|
|
|
var x = 22 + ((i - 108) % 8)
|
|
|
|
|
var y = (i - 108) / 8
|
|
|
|
|
if data[i] > 0 {
|
|
|
|
|
out[y][x] = '1'
|
|
|
|
|
} else {
|
|
|
|
|
out[y][x] = '0'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Slot type second half
|
|
|
|
|
for i := 156; i < 166; i++ {
|
|
|
|
|
var x = 31 + ((i - 156) % 2)
|
|
|
|
|
var y = (i - 156) / 2
|
|
|
|
|
if data[i] > 0 {
|
|
|
|
|
out[y][x] = '1'
|
|
|
|
|
} else {
|
|
|
|
|
out[y][x] = '0'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Info second half
|
|
|
|
|
for i := 166; i < 264; i++ {
|
|
|
|
|
var x = 34 + ((i - 166) % 16)
|
|
|
|
|
var y = ((i - 166) / 16)
|
|
|
|
|
if x > 41 {
|
|
|
|
|
x++
|
|
|
|
|
}
|
|
|
|
|
if data[i] > 0 {
|
|
|
|
|
out[y][x] = '1'
|
|
|
|
|
} else {
|
|
|
|
|
out[y][x] = '0'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fmt.Println("|------INFO1------|ST|--SYNC--|ST|------INFO2------|")
|
|
|
|
|
for _, row := range out {
|
|
|
|
|
fmt.Println(string(row))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dumpSync(p *ipsc.Packet, desc string) {
|
|
|
|
|
sync := dmr.ExtractSyncBits(p.PayloadBits)
|
|
|
|
|
patt := dmr.SyncPattern(sync)
|
|
|
|
|
fmt.Printf("dmr[%d->%d]: ts%d got %s:\n", p.SrcID, p.DstID, p.Timeslot+1, desc)
|
|
|
|
|
fmt.Printf(" sync pattern: %s\n", dmr.SyncPatternName[patt])
|
|
|
|
|
if patt == dmr.SyncPatternUnknown {
|
|
|
|
|
fmt.Print(hex.Dump(sync.Bytes()))
|
|
|
|
|
for i, b := range sync {
|
|
|
|
|
sync[i] = b ^ 1
|
|
|
|
|
}
|
|
|
|
|
fmt.Print(hex.Dump(sync.Bytes()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
slot := dmr.ExtractSlotType(p.PayloadBits)
|
|
|
|
|
var (
|
|
|
|
|
codeword uint32
|
|
|
|
|
bursttype uint32
|
|
|
|
|
payload = make([]byte, 12)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
codeword = (uint32(slot[0]) << 11) | (uint32(slot[1]) << 3) | uint32(slot[2])>>5
|
|
|
|
|
bursttype = uint32(slot[0]) & 7
|
|
|
|
|
fmt.Printf("codeword: %#08x, bursttype: %#04x\n", codeword, bursttype)
|
|
|
|
|
fec.Golay_23_12_Correct(&codeword)
|
|
|
|
|
fmt.Printf("codeword: %#08x (after correcting)\n", codeword)
|
|
|
|
|
codeword &= 0x0f
|
|
|
|
|
fmt.Printf("codeword: %#08x (after masking)\n", codeword)
|
|
|
|
|
bursttype ^= codeword
|
|
|
|
|
var errors int
|
|
|
|
|
if bursttype&1 > 0 {
|
|
|
|
|
errors++
|
|
|
|
|
}
|
|
|
|
|
if bursttype&2 > 0 {
|
|
|
|
|
errors++
|
|
|
|
|
}
|
|
|
|
|
if bursttype&4 > 0 {
|
|
|
|
|
errors++
|
|
|
|
|
}
|
|
|
|
|
if bursttype&8 > 0 {
|
|
|
|
|
errors++
|
|
|
|
|
}
|
|
|
|
|
bursttype = codeword
|
|
|
|
|
//fmt.Printf("%d errors detected, burstype: %08x (%d)\n", errors, bursttype, bursttype)
|
|
|
|
|
fmt.Printf(" burst type: %s (%d), %d errors\n", bursttypes[bursttype], bursttype, errors)
|
|
|
|
|
|
|
|
|
|
if bursttype < 7 {
|
|
|
|
|
if err := bptc.Process(dmr.ExtractInfoBits(p.PayloadBits), payload); err != nil {
|
|
|
|
|
fmt.Printf(" payload error: %v\n", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
fmt.Printf(" payload: (%d bytes)\n", len(payload))
|
|
|
|
|
fmt.Print(" " + hex.Dump(payload))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fid := payload[1]
|
|
|
|
|
fidm := fidMap[fid]
|
|
|
|
|
|
|
|
|
|
switch bursttype {
|
|
|
|
|
case 1, 2:
|
|
|
|
|
dumpFCLO(payload, fidm)
|
|
|
|
|
case 6:
|
|
|
|
|
dumpDataHeader(payload)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
if err := fec.Golay_20_8_Check(slot); err != nil {
|
|
|
|
|
fmt.Printf("%v\n", err)
|
|
|
|
|
fmt.Print(hex.Dump(slot.Bytes()))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cc := (slot[0] << 3) | (slot[1] << 2) | (slot[2] << 1) | slot[3]
|
|
|
|
|
dt := (slot[4] << 3) | (slot[5] << 2) | (slot[6] << 1) | slot[7]
|
|
|
|
|
fmt.Printf("cc: %d, data type: %d\n", cc, dt)
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func rc() *homebrew.RepeaterConfiguration {
|
|
|
|
|
return &homebrew.RepeaterConfiguration{
|
|
|
|
|
Callsign: "PI1BOL",
|
|
|
|
@ -291,52 +37,70 @@ func rc() *homebrew.RepeaterConfiguration {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dumpRaw(raw []byte) {
|
|
|
|
|
fmt.Printf("dump raw frame of %d bytes\n", len(raw))
|
|
|
|
|
p, err := homebrew.ParseData(raw)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf(" parse error: %v\n", err)
|
|
|
|
|
func main() {
|
|
|
|
|
dumpFile := flag.String("dump", "", "dump file")
|
|
|
|
|
pcapFile := flag.String("pcap", "", "PCAP file")
|
|
|
|
|
liveFile := flag.String("live", "", "live configuration file")
|
|
|
|
|
showRaw := flag.Bool("raw", false, "show raw frames")
|
|
|
|
|
audioTS := flag.Int("audiots", 0, "play audio from time slot (1 or 2)")
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
|
|
if *audioTS > 2 {
|
|
|
|
|
log.Fatalf("invalid time slot %d\n", *audioTS)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
dumpPacket(p)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dumpPacket(p *ipsc.Packet) {
|
|
|
|
|
fmt.Print(p.Dump())
|
|
|
|
|
dumpData(p.PayloadBits)
|
|
|
|
|
r := repeater.New()
|
|
|
|
|
|
|
|
|
|
if *audioTS > 0 {
|
|
|
|
|
ambeframe := make(chan float32)
|
|
|
|
|
|
|
|
|
|
switch p.SlotType {
|
|
|
|
|
case ipsc.VoiceLCHeader:
|
|
|
|
|
dumpSync(p, "voice LC header")
|
|
|
|
|
case ipsc.TerminatorWithLC:
|
|
|
|
|
dumpSync(p, "terminator with LC")
|
|
|
|
|
case ipsc.CSBK:
|
|
|
|
|
dumpSync(p, "CSBK")
|
|
|
|
|
case ipsc.VoiceDataA:
|
|
|
|
|
dumpSync(p, "voice A")
|
|
|
|
|
case ipsc.VoiceDataB:
|
|
|
|
|
dumpSync(p, "voice B")
|
|
|
|
|
case ipsc.VoiceDataC:
|
|
|
|
|
dumpSync(p, "voice C")
|
|
|
|
|
case ipsc.VoiceDataD:
|
|
|
|
|
dumpSync(p, "voice D")
|
|
|
|
|
case ipsc.VoiceDataE:
|
|
|
|
|
dumpSync(p, "voice E")
|
|
|
|
|
case ipsc.VoiceDataF:
|
|
|
|
|
dumpSync(p, "voice F")
|
|
|
|
|
vs := dsd.NewAMBEVoiceStream(3)
|
|
|
|
|
r.VoiceFrameFunc = func(p *ipsc.Packet, bits bit.Bits) {
|
|
|
|
|
var in = make([]byte, len(bits))
|
|
|
|
|
for i, b := range bits {
|
|
|
|
|
in[i] = byte(b)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Print("\n---\n\n")
|
|
|
|
|
samples, err := vs.Decode(in)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("error decoding AMBE3000 frame: %v\n", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
fmt.Printf("%v\n", samples)
|
|
|
|
|
for _, sample := range samples {
|
|
|
|
|
ambeframe <- sample
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
dumpFile := flag.String("dump", "", "dump file")
|
|
|
|
|
liveFile := flag.String("live", "", "live configuration file")
|
|
|
|
|
showRaw := flag.Bool("raw", false, "show raw frames")
|
|
|
|
|
flag.Parse()
|
|
|
|
|
portaudio.Initialize()
|
|
|
|
|
defer portaudio.Terminate()
|
|
|
|
|
h, err := portaudio.DefaultHostApi()
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := repeater.New()
|
|
|
|
|
if *liveFile != "" {
|
|
|
|
|
p := portaudio.LowLatencyParameters(nil, h.DefaultOutputDevice)
|
|
|
|
|
p.SampleRate = 8000
|
|
|
|
|
p.Output.Channels = 1
|
|
|
|
|
stream, err := portaudio.OpenStream(p, func(out []float32) {
|
|
|
|
|
for i := range out {
|
|
|
|
|
out[i] = <-ambeframe
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("error streaming: %v\n", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer stream.Close()
|
|
|
|
|
if err := stream.Start(); err != nil {
|
|
|
|
|
log.Printf("error streaming: %v\n", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch {
|
|
|
|
|
case *liveFile != "":
|
|
|
|
|
log.Printf("going in live mode using %q\n", *liveFile)
|
|
|
|
|
f, err := os.Open(*liveFile)
|
|
|
|
|
if err != nil {
|
|
|
|
@ -362,8 +126,7 @@ func main() {
|
|
|
|
|
protocol.Dump = true
|
|
|
|
|
panic(protocol.Run())
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
case *dumpFile != "":
|
|
|
|
|
i, err := os.Open(*dumpFile)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
@ -394,5 +157,33 @@ func main() {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case *pcapFile != "":
|
|
|
|
|
var (
|
|
|
|
|
handle *pcap.Handle
|
|
|
|
|
err error
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if handle, err = pcap.OpenOffline(*pcapFile); err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
defer handle.Close()
|
|
|
|
|
|
|
|
|
|
dec := gopacket.DecodersByLayerName["Ethernet"]
|
|
|
|
|
source := gopacket.NewPacketSource(handle, dec)
|
|
|
|
|
for packet := range source.Packets() {
|
|
|
|
|
raw := packet.ApplicationLayer().Payload()
|
|
|
|
|
if *showRaw {
|
|
|
|
|
fmt.Println("raw packet:")
|
|
|
|
|
fmt.Print(hex.Dump(raw))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p, err := homebrew.ParseData(raw)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf(" parse error: %v\n", err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
r.Stream(p)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|