-
Notifications
You must be signed in to change notification settings - Fork 36
/
handler.go
238 lines (205 loc) · 6.37 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// SPDX-FileCopyrightText: 2021 Open Networking Foundation <info@opennetworking.org>
//
// SPDX-License-Identifier: Apache-2.0
package pdusessworker
import (
"encoding/hex"
"fmt"
"net"
"time"
"github.com/omec-project/gnbsim/common"
realuectx "github.com/omec-project/gnbsim/realue/context"
"github.com/omec-project/gnbsim/util/test"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
)
const (
ICMP_HEADER_LEN int = 8
/*ipv4 package requires ipv4 header length in terms of number of bytes,
however it later converts it into number of 32 bit words
*/
IPV4_MIN_HEADER_LEN int = 20
)
func HandleInitEvent(pduSess *realuectx.PduSession,
intfcMsg common.InterfaceMessage,
) (err error) {
msg := intfcMsg.(*common.UeMessage)
pduSess.WriteGnbChan = msg.CommChan
pduSess.LastDataPktRecvd = false
return nil
}
func SendIcmpEchoRequest(pduSess *realuectx.PduSession) (err error) {
pduSess.Log.Traceln("Sending UL ICMP ping message")
icmpPayload, err := hex.DecodeString("8c870d0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637")
if err != nil {
pduSess.Log.Errorln("Failed to decode icmp hexString ")
return err
}
icmpPayloadLen := len(icmpPayload)
pduSess.Log.Traceln("ICMP payload size:", icmpPayloadLen)
ipv4hdr := ipv4.Header{
Version: 4,
Len: IPV4_MIN_HEADER_LEN,
Protocol: 1,
Flags: 0,
TotalLen: IPV4_MIN_HEADER_LEN + ICMP_HEADER_LEN + icmpPayloadLen,
TTL: 64,
Src: pduSess.PduAddress, // ue IP address
Dst: net.ParseIP(pduSess.DefaultAs).To4(), // upstream router interface connected to Gi
ID: 1,
}
checksum := test.CalculateIpv4HeaderChecksum(&ipv4hdr)
ipv4hdr.Checksum = int(checksum)
v4HdrBuf, err := ipv4hdr.Marshal()
if err != nil {
pduSess.Log.Errorln("ipv4hdr header marshal failed")
return err
}
icmpMsg := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: 12394, Seq: pduSess.GetNextSeqNum(),
Data: icmpPayload,
},
}
b, err := icmpMsg.Marshal(nil)
if err != nil {
pduSess.Log.Errorln("Failed to marshal icmp message")
return err
}
payload := append(v4HdrBuf, b...)
userDataMsg := &common.UserDataMessage{}
userDataMsg.Event = common.UL_UE_DATA_TRANSFER_EVENT
userDataMsg.Payload = payload
pduSess.WriteGnbChan <- userDataMsg
pduSess.TxDataPktCount++
pduSess.Log.Traceln("Sent UL ICMP ping message")
return nil
}
func HandleIcmpMessage(pduSess *realuectx.PduSession,
icmpPkt []byte,
) (err error) {
icmpMsg, err := icmp.ParseMessage(1, icmpPkt)
if err != nil {
return fmt.Errorf("failed to parse icmp message:%v", err)
}
switch icmpMsg.Type {
case ipv4.ICMPTypeEchoReply:
echpReply := icmpMsg.Body.(*icmp.Echo)
if echpReply == nil {
return fmt.Errorf("icmp echo reply is nil")
}
pduSess.Log.Infof("Received ICMP Echo Reply, ID:%v, Seq:%v",
echpReply.ID, echpReply.Seq)
pduSess.RxDataPktCount++
if pduSess.ReqDataPktInt == 0 {
if pduSess.TxDataPktCount < pduSess.ReqDataPktCount {
err := SendIcmpEchoRequest(pduSess)
if err != nil {
return fmt.Errorf("failed to send icmp message:%v", err)
}
} else {
msg := &common.UuMessage{}
msg.Event = common.DATA_PKT_GEN_SUCCESS_EVENT
pduSess.WriteUeChan <- msg
pduSess.Log.Traceln("Sent Data Packet Generation Success Event")
}
}
default:
return fmt.Errorf("unsupported icmp message type:%v", icmpMsg.Type)
}
return nil
}
func HandleDlMessage(pduSess *realuectx.PduSession,
msg common.InterfaceMessage,
) (err error) {
pduSess.Log.Traceln("Handling DL user data packet from gNb")
if msg.GetEventType() == common.LAST_DATA_PKT_EVENT {
pduSess.Log.Debugln("Received last downlink data packet")
pduSess.LastDataPktRecvd = true
return nil
}
dataMsg := msg.(*common.UserDataMessage)
if dataMsg.Qfi != nil {
pduSess.Log.Infoln("Received QFI value in downlink user data packet:", *dataMsg.Qfi)
}
ipv4Hdr, err := ipv4.ParseHeader(dataMsg.Payload)
if err != nil {
return fmt.Errorf("failed to parse ipv4 header:%v", err)
}
switch ipv4Hdr.Protocol {
/* Currently supporting ICMP protocol */
case 1:
err = HandleIcmpMessage(pduSess, dataMsg.Payload[ipv4Hdr.Len:])
if err != nil {
return fmt.Errorf("failed to handle icmp message:%v", err)
}
default:
return fmt.Errorf("unsupported ipv4 protocol:%v", ipv4Hdr.Protocol)
}
return nil
}
func HandleDataPktGenRequestEvent(pduSess *realuectx.PduSession,
intfcMsg common.InterfaceMessage,
) (err error) {
cmd := intfcMsg.(*common.UeMessage)
pduSess.ReqDataPktCount = cmd.UserDataPktCount
pduSess.ReqDataPktInt = cmd.UserDataPktInterval
pduSess.DefaultAs = cmd.DefaultAs
if pduSess.ReqDataPktInt == 0 {
err = SendIcmpEchoRequest(pduSess)
if err != nil {
return fmt.Errorf("failed to send icmp echo req:%v", err)
}
} else {
go func(pduSess *realuectx.PduSession) {
for pduSess.TxDataPktCount < pduSess.ReqDataPktCount {
err := SendIcmpEchoRequest(pduSess)
if err != nil {
pduSess.Log.Errorf("failed to send icmp echo req: %v", err)
return // Exit the goroutine on error
}
time.Sleep(time.Duration(pduSess.ReqDataPktInt) * time.Second)
}
msg := &common.UuMessage{}
msg.Event = common.DATA_PKT_GEN_SUCCESS_EVENT
pduSess.WriteUeChan <- msg
pduSess.Log.Traceln("Sent Data Packet Generation Success Event")
}(pduSess)
}
return nil
}
func HandleConnectionReleaseRequestEvent(pduSess *realuectx.PduSession,
intfcMsg common.InterfaceMessage,
) (err error) {
userDataMsg := &common.UserDataMessage{}
userDataMsg.Event = common.LAST_DATA_PKT_EVENT
pduSess.WriteGnbChan <- userDataMsg
// Releasing the reference so as to be freed by Garbage Collector
pduSess.WriteGnbChan = nil
return nil
}
func HandleQuitEvent(pduSess *realuectx.PduSession,
intfcMsg common.InterfaceMessage,
) (err error) {
if pduSess.WriteGnbChan != nil {
userDataMsg := &common.UserDataMessage{}
userDataMsg.Event = common.LAST_DATA_PKT_EVENT
pduSess.WriteGnbChan <- userDataMsg
pduSess.WriteGnbChan = nil
}
// Drain all the messages until END MARKER is received.
// This ensures that the transmitting go routine is not blocked while
// sending data on this channel
if !pduSess.LastDataPktRecvd {
for pkt := range pduSess.ReadDlChan {
if pkt.GetEventType() == common.LAST_DATA_PKT_EVENT {
pduSess.Log.Debugln("Received last downlink data packet")
break
}
}
}
pduSess.WriteUeChan = nil
pduSess.Log.Infoln("Pdu Session terminated")
return nil
}