This repository has been archived by the owner on Apr 11, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 24
/
event_exposure.go
305 lines (281 loc) · 9.39 KB
/
event_exposure.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
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
package amf_producer
import (
"github.com/sirupsen/logrus"
"free5gc/lib/openapi/models"
"free5gc/src/amf/amf_context"
"free5gc/src/amf/gmm/gmm_state"
"free5gc/src/amf/logger"
"strconv"
"time"
)
var HttpLog *logrus.Entry
func init() {
// init Pool
HttpLog = logger.HttpLog
}
// TODO: handle event filter
func CreateAMFEventSubscription(context *amf_context.AMFContext, request models.AmfCreateEventSubscription, recieveTime time.Time) (response *models.AmfCreatedEventSubscription, err models.ProblemDetails) {
response = &models.AmfCreatedEventSubscription{}
subscription := request.Subscription
contextEventSubscription := &amf_context.AMFContextEventSubscription{}
contextEventSubscription.EventSubscription = *subscription
newSubscriptionID := strconv.Itoa(context.EventSubscriptionIDGenerator)
var isImmediate bool
var immediateFlags []bool
var reportlist []models.AmfEventReport
// store subscription in amf_context
ueEventSubscription := amf_context.AmfUeEventSubscription{}
ueEventSubscription.EventSubscription = &contextEventSubscription.EventSubscription
ueEventSubscription.Timestamp = recieveTime
if subscription.Options != nil && subscription.Options.Trigger == models.AmfEventTrigger_CONTINUOUS {
ueEventSubscription.RemainReports = new(int32)
*ueEventSubscription.RemainReports = subscription.Options.MaxReports
}
for _, events := range *subscription.EventList {
immediateFlags = append(immediateFlags, events.ImmediateFlag)
if events.ImmediateFlag {
isImmediate = true
}
}
if subscription.AnyUE {
contextEventSubscription.IsAnyUe = true
ueEventSubscription.AnyUe = true
for _, ue := range context.UePool {
ue.EventSubscriptionsInfo[newSubscriptionID] = new(amf_context.AmfUeEventSubscription)
*ue.EventSubscriptionsInfo[newSubscriptionID] = ueEventSubscription
contextEventSubscription.UeSupiList = append(contextEventSubscription.UeSupiList, ue.Supi)
}
} else if subscription.GroupId != "" {
contextEventSubscription.IsGroupUe = true
ueEventSubscription.AnyUe = true
for _, ue := range context.UePool {
if ue.GroupID == subscription.GroupId {
ue.EventSubscriptionsInfo[newSubscriptionID] = new(amf_context.AmfUeEventSubscription)
*ue.EventSubscriptionsInfo[newSubscriptionID] = ueEventSubscription
contextEventSubscription.UeSupiList = append(contextEventSubscription.UeSupiList, ue.Supi)
}
}
} else {
if ue, ok := context.UePool[subscription.Supi]; !ok {
err.Status = 403
err.Cause = "UE_NOT_SERVED_BY_AMF"
return nil, err
} else {
ue.EventSubscriptionsInfo[newSubscriptionID] = new(amf_context.AmfUeEventSubscription)
*ue.EventSubscriptionsInfo[newSubscriptionID] = ueEventSubscription
contextEventSubscription.UeSupiList = append(contextEventSubscription.UeSupiList, ue.Supi)
}
}
// delete subscription
if subscription.Options != nil {
contextEventSubscription.Expiry = subscription.Options.Expiry
}
context.EventSubscriptionIDGenerator++
context.EventSubscriptions[newSubscriptionID] = contextEventSubscription
// build response
response.Subscription = subscription
response.SubscriptionId = newSubscriptionID
// for immediate use
if subscription.AnyUE {
for _, ue := range context.UePool {
if isImmediate {
subReports(ue, newSubscriptionID)
}
for i, flag := range immediateFlags {
if flag {
report, ok := NewAmfEventReport(ue, (*subscription.EventList)[i].Type, newSubscriptionID)
if ok {
reportlist = append(reportlist, report)
}
}
}
// delete subscription
if len := len(reportlist); len > 0 && (!reportlist[len-1].State.Active) {
delete(ue.EventSubscriptionsInfo, newSubscriptionID)
}
}
} else if subscription.GroupId != "" {
for _, ue := range context.UePool {
if isImmediate {
subReports(ue, newSubscriptionID)
}
if ue.GroupID == subscription.GroupId {
for i, flag := range immediateFlags {
if flag {
report, ok := NewAmfEventReport(ue, (*subscription.EventList)[i].Type, newSubscriptionID)
if ok {
reportlist = append(reportlist, report)
}
}
}
// delete subscription
if len := len(reportlist); len > 0 && (!reportlist[len-1].State.Active) {
delete(ue.EventSubscriptionsInfo, newSubscriptionID)
}
}
}
} else {
ue := context.UePool[subscription.Supi]
if isImmediate {
subReports(ue, newSubscriptionID)
}
for i, flag := range immediateFlags {
if flag {
report, ok := NewAmfEventReport(ue, (*subscription.EventList)[i].Type, newSubscriptionID)
if ok {
reportlist = append(reportlist, report)
}
}
}
// delete subscription
if len := len(reportlist); len > 0 && (!reportlist[len-1].State.Active) {
delete(ue.EventSubscriptionsInfo, newSubscriptionID)
}
}
if len(reportlist) > 0 {
response.ReportList = reportlist
// delete subscription
if !reportlist[0].State.Active {
delete(context.EventSubscriptions, newSubscriptionID)
}
}
return
}
func DeleteAMFEventSubscription(context *amf_context.AMFContext, subscriptionId string) (err models.ProblemDetails) {
contextSubscription, ok := context.EventSubscriptions[subscriptionId]
if !ok {
err.Status = 404
err.Cause = "SUBSCRIPTION_NOT_FOUND"
return
}
for _, supi := range contextSubscription.UeSupiList {
ue, ok := context.UePool[supi]
if ok {
delete(ue.EventSubscriptionsInfo, subscriptionId)
}
}
delete(context.EventSubscriptions, subscriptionId)
return
}
func ModifyAMFEventSubscription(context *amf_context.AMFContext, subscriptionId string, request models.ModifySubscriptionRequest) (err models.ProblemDetails) {
contextSubscription, ok := context.EventSubscriptions[subscriptionId]
if !ok {
err.Status = 404
err.Cause = "SUBSCRIPTION_NOT_FOUND"
return
}
if request.OptionItem != nil {
contextSubscription.Expiry = request.OptionItem.Value
} else if request.SubscriptionItemInner != nil {
subscription := &contextSubscription.EventSubscription
if !contextSubscription.IsAnyUe && !contextSubscription.IsGroupUe {
if _, ok := context.UePool[subscription.Supi]; !ok {
err.Status = 403
err.Cause = "UE_NOT_SERVED_BY_AMF"
return err
}
}
op := request.SubscriptionItemInner.Op
index, _ := strconv.Atoi(request.SubscriptionItemInner.Path[11:])
lists := (*subscription.EventList)
len := len(*subscription.EventList)
switch op {
case "replace":
event := *request.SubscriptionItemInner.Value
if index < len {
(*subscription.EventList)[index] = event
}
case "remove":
if index < len {
*subscription.EventList = append(lists[:index], lists[index+1:]...)
}
case "add":
event := *request.SubscriptionItemInner.Value
*subscription.EventList = append(lists, event)
}
}
return
}
func subReports(ue *amf_context.AmfUe, subscriptionId string) {
remainReport := ue.EventSubscriptionsInfo[subscriptionId].RemainReports
if remainReport == nil {
return
}
*remainReport--
}
// DO NOT handle AmfEventType_PRESENCE_IN_AOI_REPORT and AmfEventType_UES_IN_AREA_REPORT(about area)
func NewAmfEventReport(ue *amf_context.AmfUe, Type models.AmfEventType, subscriptionId string) (report models.AmfEventReport, ok bool) {
ueSubscription, ok := ue.EventSubscriptionsInfo[subscriptionId]
if !ok {
return
}
report.AnyUe = ueSubscription.AnyUe
report.Supi = ue.Supi
report.Type = Type
report.TimeStamp = &ueSubscription.Timestamp
report.State = new(models.AmfEventState)
mode := ueSubscription.EventSubscription.Options
if mode == nil {
report.State.Active = true
} else if mode.Trigger == models.AmfEventTrigger_ONE_TIME {
report.State.Active = false
} else if *ueSubscription.RemainReports <= 0 {
report.State.Active = false
} else {
report.State.Active = getDuration(mode.Expiry, &report.State.RemainDuration)
if report.State.Active {
report.State.RemainReports = *ueSubscription.RemainReports
}
}
switch Type {
case models.AmfEventType_LOCATION_REPORT:
report.Location = &ue.Location
// case models.AmfEventType_PRESENCE_IN_AOI_REPORT:
// report.AreaList = (*subscription.EventList)[eventIndex].AreaList
case models.AmfEventType_TIMEZONE_REPORT:
report.Timezone = ue.TimeZone
case models.AmfEventType_ACCESS_TYPE_REPORT:
for accessType, sm := range ue.Sm {
if sm.Check(gmm_state.REGISTERED) {
report.AccessTypeList = append(report.AccessTypeList, accessType)
}
}
case models.AmfEventType_REGISTRATION_STATE_REPORT:
var rmInfos []models.RmInfo
for accessType, sm := range ue.Sm {
rmInfo := models.RmInfo{
RmState: models.RmState_DEREGISTERED,
AccessType: accessType,
}
if sm.Check(gmm_state.REGISTERED) {
rmInfo.RmState = models.RmState_REGISTERED
}
rmInfos = append(rmInfos, rmInfo)
}
report.RmInfoList = rmInfos
case models.AmfEventType_CONNECTIVITY_STATE_REPORT:
report.CmInfoList = ue.GetCmInfo()
case models.AmfEventType_REACHABILITY_REPORT:
report.Reachability = ue.Reachability
case models.AmfEventType_SUBSCRIBED_DATA_REPORT:
report.SubscribedData = &ue.SubscribedData
case models.AmfEventType_COMMUNICATION_FAILURE_REPORT:
// TODO : report.CommFailure
case models.AmfEventType_SUBSCRIPTION_ID_CHANGE:
report.SubscriptionId = subscriptionId
case models.AmfEventType_SUBSCRIPTION_ID_ADDITION:
report.SubscriptionId = subscriptionId
}
return
}
func getDuration(expiry *time.Time, remainDuration *int32) bool {
if expiry != nil {
if time.Now().After(*expiry) {
return false
} else {
duration := time.Until(*expiry)
*remainDuration = int32(duration.Seconds())
}
}
return true
}