· 6 years ago · Jan 28, 2020, 06:34 PM
1/**************************************************************************
2*
3* Filename: lrdc_coa.c
4*
5* Author: Hans De Vleeschouwer
6* Created: Wed Nov 13 CEST 2019
7*
8* Description: Lte Radius COA handling on CPM
9*
10***************************************************************************
11*
12* Source Control System Information
13*
14* $Id$
15*
16***************************************************************************
17*
18* Copyright (c) 2019 Nokia
19*
20**************************************************************************/
21
22#ifdef RCSID
23static const char rcsid[] = "$Id$";
24#endif
25
26#ifndef LC_FILE_ID
27#define LC_FILE_ID 143
28#endif
29
30#include <semLib.h>
31#include <string.h>
32#include <taskLib.h>
33#include <tickLib.h>
34#include <vxAtomicLib.h>
35
36#include "common/fs_mem.h"
37#include "common/gen/mod_lrdc_coa.h"
38#include "common/gen/timos_feature_mg_cups_bng_coa.h"
39#include "common/gen/timos_feature_smf_fixed_access.h"
40#include "common/task.h"
41#include "lte_mgmt/vrifdb.h"
42#include "lte_rad_cpm/lrdc_coa.h"
43#include "radius/radius_ng.h"
44#include "bsp/md5.h"
45
46/*-------------------------------------------------------------------------------------*/
47/* Macros Definitions */
48/*-------------------------------------------------------------------------------------*/
49#define LDRC_COA_MAX_NUM_TASKS 4
50
51#define LDRC_COA_EVENT(fmt, args...) TRACE_EVENT(MOD_LRDC_COA, NOCLASS, fmt, ##args)
52#define LDRC_COA_UEVENT(fmt, args...) TRACE_UNUSUALEVENT(MOD_LRDC_COA, NOCLASS, fmt, ##args)
53#define LDRC_COA_ERROR(fmt, args...) TRACE_ERROR(MOD_LRDC_COA, NOCLASS, fmt, ##args)
54#define LDRC_COA_BERROR(fmt, args...) BTRACE_ERROR(MOD_LRDC_COA, NOCLASS, fmt, ##args)
55
56/* Checks a condition and jumps to a label after tracing. */
57#define CHECK_ERROR(condition, flag, trace, args...) \
58 if (condition) \
59 { \
60 LDRC_COA_EVENT(trace, ##args); \
61 goto flag; \
62 }
63
64/*-------------------------------------------------------------------------------------*/
65/* Type Definitions */
66/*-------------------------------------------------------------------------------------*/
67
68/* COA message received in a lrdc-coa task
69 * ======================================*/
70typedef enum
71{
72 LRDC_COA_MSG_INCOMING_COA,
73 LRDC_COA_MSG_INCOMING_MAX,
74} tlrdcCoa_MsgType;
75
76typedef struct lrdcCoa_CoaMsg_incoming_coa
77{
78 tRadiusAttributeHandle AttrHandle;
79 tUint8 *pDiscMsg;
80 tUint16 msgLen;
81 tIpAnyAddr srcAnyAddr;
82 tIpAnyAddr dstAnyAddr;
83 tLrdcCoa_VrIfEntry vrIfEntry;
84 tUint16 srcPort;
85} tlrdcCoa_CoaMsg_incoming_coa;
86
87typedef struct lrdcCoa_CoaMsg
88{
89 tTMsg link; /* to link in msg Q */
90 tlrdcCoa_MsgType type;
91
92 union
93 {
94 tlrdcCoa_CoaMsg_incoming_coa coaRcvd;
95 } msgData;
96} tlrdcCoa_CoaMsg;
97
98/* Coa Packet Header and Attributes
99 * =================================
100 * Make sure there is no allignment or padding introduced by the compiler
101 * This way we can cast the received CoA packet pointer directly to this
102 * struct to parse the packet. */
103#pragma pack(push, 1)
104
105typedef struct
106{
107 tUint8 type;
108 tUint8 length;
109 tUint8 value[];
110} tLrdcCoa_Attr;
111
112typedef struct
113{
114 tUint8 code; // byte 1
115 tUint8 identifier; // byte 2
116 tUint16 length; // byte 4
117 tUint8 authenticator[AUTH_VECTOR_LEN]; // byte 20
118 tUint8 attributes[];
119} tLrdcCoaPacket;
120
121_Static_assert((sizeof(tLrdcCoaPacket) == AUTH_HDR_LEN),
122 "tLrdcCoaPacket should have size AUTH_HDR_LEN");
123
124#pragma pack(pop)
125
126/* tlrdcCoa_idData : Identification data from CoA packet
127 * ==========================================================*/
128typedef struct
129{
130 tUint8 length;
131 tUint8 bytes[];
132} tLrdcCoa_varLenBytes;
133
134typedef union
135{
136 tUint32 integer;
137 tIpAddr ipAddr;
138 tIp6Addr *ip6Addr;
139 tLrdcCoa_varLenBytes *varLenBytes;
140} tLrdcCoa_attrVal;
141
142typedef struct
143{
144 tLrdcCoa_varLenBytes *username;
145 tLrdcCoa_varLenBytes *acctSessionId;
146 tIp6Addr *timetraIpv6Address;
147 tUint32 timetraServId;
148 tLrdcCoa_varLenBytes *timetraSubscIdStr;
149 tLrdcCoa_varLenBytes *framedIpv6Prefix;
150 tLrdcCoa_varLenBytes *delegatedIpv6Prefix;
151 tIpAddr framedIpAddress;
152} tlrdcCoa_idData;
153
154/* tlrdcCoa_TaskData : Data kept per COA task instance
155 * ==================================================*/
156typedef struct
157{
158 tUint32 a;
159
160} tlrdcCoa_TaskData;
161
162/*-------------------------------------------------------------------------------------*/
163/* Task Global/Static Variables */
164/*-------------------------------------------------------------------------------------*/
165
166/* Main semaphore controlling the receiving msg queue */
167PRIVATE SEM_ID lrdcCoa_MainSem;
168
169/* Message RX queue */
170PRIVATE tTMsgQ rlrdcCoa_MsgQ; // tlrdcCoa_CoaMsg
171
172/* stats */
173PRIVATE tUint32 rlrdcCoa_NumMsgs;
174
175/* Dfrag manager */
176PRIVATE t_fsmem_mgr_handle rlrdcCoa_DfragMgr;
177
178/* Radius-NG handle to be used by ldrcCoaTask */
179PUBLIC tRadiusUserHandle ldrcCoa_radiusNgHandle = NULL;
180
181/* Immutable AVL tree to store Virtual Router/Interface -> gwId association.
182 * This tree is recreated and immutably replaced every time the config changes.
183 * We didn't use the configuration trees (one for each PDN) for performance reasons.
184 */
185PRIVATE tAvlpTree *pLrdcCoa_VrIfTable = NULL;
186PRIVATE tUint32 totalNbrOfVrIfEntryMalloc;
187PRIVATE tUint32 totalNbrOfVrIfEntryFrees;
188PRIVATE tUint32 nbrOfOperTreesCreated;
189PRIVATE tUint32 nbrOfOperTreesFreed;
190PRIVATE tUint32 nbrOfOperationalTreeSwaps;
191
192/* CoA packet statistics */
193#define LRDC_INCSTAT(v) vxAtomicInc(&v)
194PRIVATE int coaPctsReceived;
195PRIVATE int coaPctsRejectedSize;
196PRIVATE int coaPctsRejectedAuth;
197PRIVATE int coaPctsRejectedAttr;
198tLrdcCoaPacket *coaLatestPct;
199
200/*-------------------------------------------------------------------------------------*/
201/* PRIVATE Function Prototypes */
202/*-------------------------------------------------------------------------------------*/
203typedef void (*tParseAttrCb)(tLrdcCoa_Attr *, tlrdcCoa_idData *);
204PRIVATE_INLINE tStatus ldrcCoa_parseAttrs(tUint8 *, int , tlrdcCoa_idData *, tParseAttrCb);
205
206/*-------------------------------------------------------------------------------------*/
207/* PRIVATE Functions */
208/*-------------------------------------------------------------------------------------*/
209
210/*
211 *==============================================================================
212 * ldrcCoa_Malloc
213 *==============================================================================
214 */
215PRIVATE void *ldrcCoa_Malloc(size_t size)
216{
217 return dfrag_malloc(size, rlrdcCoa_DfragMgr);
218}
219
220/*
221 *==============================================================================
222 * ldrcCoa_Calloc
223 *==============================================================================
224 */
225PRIVATE void *ldrcCoa_Calloc(unsigned int num, int size)
226{
227 return dfrag_calloc(num, size, rlrdcCoa_DfragMgr);
228}
229
230/*
231 *==============================================================================
232 * ldrcCoa_Free
233 *==============================================================================
234 */
235PRIVATE void ldrcCoa_Free(void *p)
236{
237 dfrag_free(p, rlrdcCoa_DfragMgr);
238}
239
240/*
241 *==============================================================================
242 * ldrcCoa_getNumTasks
243 *==============================================================================
244 */
245PRIVATE tUint32 ldrcCoa_getNumTasks(void)
246{
247 tInt32 numCores;
248
249 numCores = coreNumCoresForApplication() - 2; /* leave some cores for others */
250 numCores = MIN(numCores, LDRC_COA_MAX_NUM_TASKS);
251
252 return (numCores < 1) ? 1 : numCores;
253}
254
255/*
256 *==============================================================================
257 * ldrcCoa_freeMsg
258 *==============================================================================
259 */
260PRIVATE void ldrcCoa_freeMsg(tlrdcCoa_CoaMsg *pMsg)
261{
262 if (!pMsg)
263 {
264 return;
265 }
266
267 ldrcCoa_Free(pMsg);
268 rlrdcCoa_NumMsgs--;
269}
270
271/*
272 *==============================================================================
273 * ldrcCoa_InitTaskData
274 *==============================================================================
275 */
276PRIVATE tStatus ldrcCoa_InitTaskData(void)
277{
278 if (!taskIdCurrent->taskVars.pDispatch)
279 {
280 taskIdCurrent->taskVars.pDispatch = ldrcCoa_Calloc(1, sizeof(tlrdcCoa_TaskData));
281 }
282
283 return (taskIdCurrent->taskVars.pDispatch ? SUCCESS : FAIL);
284}
285
286/*
287 *==============================================================================
288 * ldrcCoa_MsgIdToStr
289 *==============================================================================
290 */
291PRIVATE const char * ldrcCoa_MsgIdToStr(tlrdcCoa_MsgType type)
292{
293 switch(type) {
294 case LRDC_COA_MSG_INCOMING_COA : return "new incoming COA msg";
295
296 default:
297 return "Unknown Message type!";
298 }
299}
300
301/*==== Attribute Value Getters======*/
302PRIVATE_INLINE void lrdcCoa_getStr(tLrdcCoa_varLenBytes **out, tLrdcCoa_Attr *pAttr)
303{
304 LDRC_COA_EVENT("attr(%d)=%.*s", pAttr->type, pAttr->length, pAttr->value);
305 *out = (tLrdcCoa_varLenBytes *)&pAttr->length; // trick
306
307}
308PRIVATE_INLINE void lrdcCoa_getInt(tUint32 *out, tLrdcCoa_Attr *pAttr)
309{
310 if (pAttr->length != 4)
311 {
312 return;
313 }
314 LDRC_COA_EVENT("attr(%d)=%d, l3en=%d", pAttr->type, *pAttr->value, pAttr->length);
315 *out = ntohl(*(tUint32 *)pAttr->value);
316}
317PRIVATE_INLINE void lrdcCoa_getIp(tIpAddr *out, tLrdcCoa_Attr *pAttr)
318{
319 lrdcCoa_getInt(out, pAttr);
320}
321PRIVATE_INLINE void lrdcCoa_getIp6(tIp6Addr **out, tLrdcCoa_Attr *pAttr)
322{
323 char ipv6FmtBuf[IPV6STRLEN];
324 FmtIp6Addr((tIp6Addr *)&pAttr->value, ipv6FmtBuf, sizeof(ipv6FmtBuf));
325
326 LDRC_COA_EVENT("Getting ip6 attribute(%d)=%s, len=%d", pAttr->type, ipv6FmtBuf, pAttr->length);
327 if (pAttr->length != 16)
328 {
329 return;
330 }
331 *out = (tIp6Addr *)&pAttr->value;
332}
333PRIVATE_INLINE void lrdcCoa_getIp6Prefix(tLrdcCoa_varLenBytes **out, tLrdcCoa_Attr *pAttr)
334{
335 LDRC_COA_EVENT("Getting Ip6Prefix(%d), len=%d", pAttr->type, pAttr->length);
336 if (pAttr->length > 18)
337 {
338 return;
339 }
340 lrdcCoa_getStr(out, pAttr);
341}
342
343/*
344 *==============================================================================
345 * ldrcCoa_parseAttrOther
346 *==============================================================================
347 * Used as a callback when parsing vendor attributes of unknown vendor
348 */
349PRIVATE_INLINE void ldrcCoa_parseAttrOther(tLrdcCoa_Attr *pAttr, tlrdcCoa_idData *pIdData)
350{
351 return;
352}
353
354/*
355 *==============================================================================
356 * ldrcCoa_parseAttrTimetra
357 *==============================================================================
358 */
359PRIVATE_INLINE void ldrcCoa_parseAttrTimetra(tLrdcCoa_Attr *pAttr, tlrdcCoa_idData *pIdData)
360{
361 switch (pAttr->type) {
362 case PW_TIMETRA_SERV_ID:
363 lrdcCoa_getInt(&pIdData->timetraServId, pAttr);
364 break;
365 case PW_TIMETRA_IPV6_ADDRESS:
366 lrdcCoa_getIp6(&pIdData->timetraIpv6Address, pAttr);
367 break;
368 case PW_TIMETRA_SUBSC_ID_STR:
369 lrdcCoa_getStr(&pIdData->timetraSubscIdStr, pAttr);
370 break;
371 }
372}
373
374/*
375 *==============================================================================
376 * ldrcCoa_parseAttrVendor
377 *==============================================================================
378 */
379PRIVATE_INLINE void ldrcCoa_parseAttrsVendor(tUint8 *pValue, int length, tlrdcCoa_idData *pIdData)
380{
381 tUint32 vendorId = ntohl(*(tUint32 *)pValue);
382 const int VND_CODE_LEN = sizeof(vendorId); // 4
383 tUint8 *pVendorAtrr = pValue + VND_CODE_LEN;
384 int vendorLen = length - VND_CODE_LEN;
385
386 LDRC_COA_EVENT("Vendor Specific @ %p len=%d", pValue, length);
387 if (vendorLen < 0)
388 {
389 LDRC_COA_EVENT("Vendor Specific attribute len < 6");
390 return;
391 }
392
393 switch (vendorId) {
394 case TIMETRA_VENDOR_ID:
395 {
396 ldrcCoa_parseAttrs(pVendorAtrr, vendorLen, pIdData, ldrcCoa_parseAttrTimetra);
397 }
398 default:
399 // For unkown vendor we just ensure attributes are formatted properly
400 LDRC_COA_EVENT("Unknown vendorId");
401 ldrcCoa_parseAttrs(pVendorAtrr, vendorLen, pIdData, ldrcCoa_parseAttrOther);
402 break;
403 }
404}
405
406/*
407 *==============================================================================
408 * ldrcCoa_parseAttribute
409 *==============================================================================
410 */
411PRIVATE_INLINE void ldrcCoa_parseAttr(tLrdcCoa_Attr *pAttr, tlrdcCoa_idData *pIdData)
412{
413 int length = pAttr->length - sizeof(*pAttr);
414
415 // RFC2866 (p12): Attribute length cannot be 0
416 if (length == 0)
417 {
418 LDRC_COA_EVENT("Attribute is empty");
419 return; // We do not enforce this
420 }
421
422 LDRC_COA_EVENT("Parsing attribute type: %d, length %d, value@%p",
423 pAttr->type, pAttr->length, pAttr->value);
424
425 switch (pAttr->type) {
426 case PW_ACCT_SESSION_ID:
427 lrdcCoa_getStr(&pIdData->acctSessionId, pAttr);
428 break;
429 case PW_FRAMED_IP_ADDRESS:
430 lrdcCoa_getIp(&pIdData->framedIpAddress, pAttr);
431 break;
432 case PW_FRAMED_IPV6_PREFIX:
433 lrdcCoa_getIp6Prefix(&pIdData->framedIpv6Prefix, pAttr);
434 break;
435 case PW_DELEGATED_IPV6_PREFIX:
436 lrdcCoa_getIp6Prefix(&pIdData->delegatedIpv6Prefix, pAttr);
437 break;
438 case PW_USER_NAME:
439 lrdcCoa_getStr(&pIdData->username, pAttr);
440 break;
441 case PW_VENDOR_SPECIFIC:
442 // check pAttr->value!
443 ldrcCoa_parseAttrsVendor(pAttr->value, length, pIdData);
444 break;
445 default:
446 break;
447 }
448}
449
450/*
451 *==============================================================================
452 * ldrcCoa_parseAttributes
453 *==============================================================================
454 * Returns the attribute starting at *ppAttrStart after checking that its length
455 * is valid.
456 * sizeLeft: size of the buffer still available to read.
457 * returned negative in case of error.
458 * RFC 2866 (p11):
459 * If an attribute is received in an Accounting-Request with an invalid
460 * Length, the entire request MUST be silently discarded.
461 */
462PRIVATE_INLINE tLrdcCoa_Attr *ldrcCoa_getAttr(tUint8 **ppAttrStart, const tUint8 *pPktEnd)
463{
464 tLrdcCoa_Attr *pAttr;
465 const int ATTR_HDR_LEN = sizeof(*pAttr);
466 const int sizeLeft = pPktEnd - *ppAttrStart;
467
468 _Static_assert(ATTR_HDR_LEN == 2, "Size of pAttr header should be 2");
469
470 // Check header
471 if (sizeLeft < ATTR_HDR_LEN)
472 {
473 return NULL; // no attributes left
474 }
475
476 // Cast to structure pointer matching coa attribute memory layout
477 pAttr = (tLrdcCoa_Attr *)*ppAttrStart;
478
479 // Check length
480 *ppAttrStart += pAttr->length;
481
482 if (pAttr->length < sizeLeft)
483 {
484 LDRC_COA_EVENT("Attribute length %d bigger than space left in packet %d",
485 pAttr->length, sizeLeft);
486 return NULL;
487 }
488
489 if (pAttr->length < ATTR_HDR_LEN)
490 {
491 LDRC_COA_EVENT("Attribute length %d smaller than header (%d)",
492 pAttr->length, ATTR_HDR_LEN);
493 return NULL;
494 }
495
496 return pAttr;
497}
498
499
500/*
501 *==============================================================================
502 * ldrcCoa_parseAttrs
503 *==============================================================================
504 */
505PRIVATE_INLINE tStatus ldrcCoa_parseAttrs(tUint8 *packet,
506 int size,
507 tlrdcCoa_idData *pIdData,
508 tParseAttrCb parseAttrCb)
509{
510 int numAttr = 0;
511 const tUint8 *packetEnd = packet + size;
512 tLrdcCoa_Attr *pAttr;
513
514 while((pAttr = ldrcCoa_getAttr(&packet, packetEnd)))
515 {
516 numAttr++;
517 parseAttrCb(pAttr, pIdData);
518 }
519
520 if (size < 0)
521 {
522 LDRC_COA_EVENT("Parsing finished in attr#%d with sizeLeft=%d",
523 numAttr, size);
524 return FAIL;
525 }
526
527 LDRC_COA_EVENT("Succesfully parsed %d attributes", numAttr);
528 return SUCCESS;
529}
530
531/*
532 *==============================================================================
533 * ldrcCoa_checkAuthenticator
534 *==============================================================================
535 * According to RFC2866,p7 referenced by RFC5176,p8:
536 * The Request Authenticator field in Accounting-Request packets contains a one-
537 * way MD5 hash calculated over a stream of octets consisting of the
538 * Code + Identifier + Length + 16 zero octets + request attributes +
539 * shared secret (where + indicates concatenation). The 16 octet MD5
540 * hash value is stored in the Authenticator field of the Accounting-Request packet.
541 */
542PRIVATE_INLINE tStatus ldrcCoa_checkAuthenticator(tLrdcCoaPacket *packet, int packetLen,
543 const tUint8 *secret, int secretLen)
544{
545 typeof(packet->authenticator) rcvdAuthenticator;
546 MD5_CTX md5Context;
547 int cmpStatus;
548
549 _Static_assert( sizeof(rcvdAuthenticator) == AUTH_VECTOR_LEN &&
550 sizeof(packet->authenticator) == AUTH_VECTOR_LEN &&
551 sizeof(md5Context.digest) == AUTH_VECTOR_LEN,
552 "Size of temporary auth array should match the header");
553
554 // RFC does not allow an empty secret
555 if (!secret || !secretLen)
556 {
557 LDRC_COA_EVENT("Secret is empty");
558 return FAIL;
559 }
560
561 LDRC_COA_EVENT("Checking authenticator: secret=%s, len=%d\n", secret, secretLen);
562
563 memcpy(rcvdAuthenticator, packet->authenticator, sizeof(rcvdAuthenticator));
564 memset(packet->authenticator, 0, sizeof(packet->authenticator));
565
566 md5Init(&md5Context);
567 md5Update(&md5Context, (tUint8 *)packet, packetLen);
568 md5Update(&md5Context, (tUint8 *)secret, secretLen);
569 md5Final(&md5Context);
570
571 memcpy(packet->authenticator, rcvdAuthenticator, sizeof(packet->authenticator));
572
573 cmpStatus = memcmp(rcvdAuthenticator, md5Context.digest, AUTH_VECTOR_LEN);
574 if (cmpStatus != 0)
575 {
576 LDRC_COA_EVENT("Auth Failed: Authenticator received(%p) and expected(%p): ",
577 rcvdAuthenticator, packet->authenticator);
578 return FAIL;
579 }
580
581 return SUCCESS;
582}
583
584/*
585 *==============================================================================
586 * ldrcCoa_checkLength
587 *==============================================================================
588 */
589PRIVATE_INLINE tStatus ldrcCoa_checkLength(int receivedLength, int packetLength)
590{
591 // Before accessing structure make sure we received at least the header.
592 if (receivedLength < AUTH_HDR_LEN)
593 {
594 LDRC_COA_EVENT("Rcvd packet length (%d) smaller than minimum (%d)",
595 receivedLength, AUTH_HDR_LEN);
596 return FAIL;
597 }
598
599 // Check minimum packet length
600 if (packetLength < AUTH_HDR_LEN)
601 {
602 LDRC_COA_EVENT("Header packet length (%d) smaller than minimum (%d)",
603 packetLength, AUTH_HDR_LEN);
604 return FAIL;
605 }
606
607 // Check maximum packet length
608 if (packetLength > AUTH_REQ_MSG_LEN)
609 {
610 LDRC_COA_EVENT("Packet length (%d) bigger than maximum (%d)",
611 packetLength, AUTH_REQ_MSG_LEN);
612 return FAIL;
613 }
614
615 // RFC5176 (p8): If the packet is shorter than the Length field
616 // indicates, it MUST be silently discarded.
617 if (receivedLength < packetLength) {
618 LDRC_COA_EVENT("Packet length (%d) differs from header value (%d)",
619 receivedLength, packetLength);
620 return FAIL;
621 }
622
623 // RFC5176 (p8): Octets outside the range of the Length field
624 // MUST be treated as padding and ignored on reception.
625 if (receivedLength > packetLength) {
626 LDRC_COA_EVENT("Ignored %d bytes considered padding acc. RFC",
627 receivedLength - packetLength);
628 }
629
630 return SUCCESS;
631}
632
633PRIVATE_INLINE void lrdcCoa_dropPkt(tRadiusAttributeHandle AttrHdl)
634{
635 // tUint8 attrs[] = {PW_ERROR_CAUSE, 6, 402}
636 tStatus status;
637
638 status = radiusNgCoAProcessDone(AttrHdl, NULL, 0, RADIUS_USER_DROP_MSG, NULL, NULL);
639}
640
641PRIVATE_INLINE void ldrcCoa_sendNack(tRadiusAttributeHandle attrHdl, tUint32 errorCause) {
642 const tUint8 ERROR_CAUSE_LEN = 6;
643 tUint8 attrs[ERROR_CAUSE_LEN];
644 tStatus status;
645 // TODO see sbmRadiusCoaProcessDone
646
647 // attrs[0] = PW_ERROR_CAUSE;
648 // attrs[1] = ERROR_CAUSE_LEN;
649 *(tUint32 *)&attrs[2] = htonl(errorCause);
650 status = radiusNgCoAProcessDone(attrHdl, attrs, sizeof(attrs),
651 RADIUS_USER_DROP_MSG, NULL, NULL);
652}
653
654/*
655 *==============================================================================
656 * ldrcCoa_parseCoa
657 *==============================================================================
658 */
659PRIVATE_INLINE void ldrcCoa_parseCoa(tlrdcCoa_CoaMsg_incoming_coa *coaContext, tlrdcCoa_idData *pIdData)
660{
661 tStatus status;
662 tLrdcCoaPacket *pPacket = (typeof(pPacket))coaContext->pDiscMsg;
663 const tUint8 *pSecret = coaContext->vrIfEntry.pSecret;
664 int receivedLength = coaContext->msgLen;
665 int packetLength = ntohs(pPacket->length);
666
667 LDRC_COA_EVENT("Parsing code=%d, id=%d, rcvdlength=%d, pctlength=%d",
668 pPacket->code, pPacket->identifier, receivedLength, packetLength);
669
670 // Save last packet for error tracing
671 coaLatestPct = pPacket;
672 LRDC_INCSTAT(coaPctsReceived);
673
674 // Check length
675 status = ldrcCoa_checkLength(receivedLength, packetLength);
676 if (status != SUCCESS)
677 {
678 // Drop the packet
679 lrdcCoa_dropPkt(coaContext->AttrHandle);
680 LRDC_INCSTAT(coaPctsRejectedSize);
681 return;
682 }
683
684 // Check authenticator
685 status = ldrcCoa_checkAuthenticator(pPacket, packetLength, pSecret, strlen(pSecret));
686 if (status != SUCCESS)
687 {
688 // Drop the packet
689 lrdcCoa_dropPkt(coaContext->AttrHandle);
690 LRDC_INCSTAT(coaPctsRejectedAuth);
691 return;
692 }
693
694 // Parse attributes
695 status = ldrcCoa_parseAttrs(pPacket->attributes, packetLength - AUTH_HDR_LEN,
696 pIdData, ldrcCoa_parseAttr);
697 // if (status != SUCCESS)
698 {
699 LRDC_INCSTAT(coaPctsRejectedAttr);
700 ldrcCoa_sendNack(coaContext->AttrHandle, PW_ERR_INVALID_REQUEST);
701 return;
702 }
703}
704
705PRIVATE tStatus ldrcCoa_findSession(tlrdcCoa_idData *pIdData)
706{
707 if (pIdData->acctSessionId)
708 { // 1 session
709
710 }
711 else if (pIdData->timetraServId)
712 { // 1 session or 508(Multiple Session Unsupported)
713 if (pIdData->framedIpAddress)
714 {
715
716 }
717 else if (pIdData->framedIpv6Prefix)
718 {
719
720 }
721 else if (pIdData->timetraIpv6Address)
722 {
723
724 }
725 else if (pIdData->delegatedIpv6Prefix)
726 {
727
728 }
729 else
730 {
731 // NACK missing attrubute 402
732 return FAIL;
733 }
734
735 }
736 else if (pIdData->username)
737 { // multiple sessions
738
739 }
740 else if (pIdData->timetraSubscIdStr)
741 { // multiple sessions
742
743 }
744 else
745 {
746 // NACK missing attrubute 402
747 return FAIL;
748 }
749
750 //if we have attrs but cant find session-> Nas id mismatch 403
751 return SUCCESS;
752}
753
754/*
755 *==============================================================================
756 * ldrcCoa_processMsg
757 *==============================================================================
758 */
759PRIVATE void ldrcCoa_processMsg(tlrdcCoa_CoaMsg *pMsg)
760{
761 tStatus status;
762 tlrdcCoa_idData pIdData = {0};
763 char buf1[40] = {}, buf2[40] = {};
764
765 LDRC_COA_EVENT("BNG COA: Type=%u (%s)", pMsg->type, ldrcCoa_MsgIdToStr(pMsg->type));
766
767 switch (pMsg->type) {
768 case LRDC_COA_MSG_INCOMING_COA:
769 /*----------------------------*/
770
771 formatIpAnyAddr_VrId(pMsg->msgData.coaRcvd.vrIfEntry.vRtrID,
772 &pMsg->msgData.coaRcvd.srcAnyAddr,
773 buf1, sizeof(buf1));
774 formatIpAnyAddr_VrId(pMsg->msgData.coaRcvd.vrIfEntry.vRtrID,
775 &pMsg->msgData.coaRcvd.dstAnyAddr,
776 buf2, sizeof(buf2));
777
778 LDRC_COA_EVENT("BNG COA: COA received in worker thread"
779 "(vrId=%d, srcPort=%d, srcIp=%s, dstIp=%s, attrHdnle=%p",
780 pMsg->msgData.coaRcvd.vrIfEntry.vRtrID,
781 pMsg->msgData.coaRcvd.srcPort,
782 buf1, buf2,
783 pMsg->msgData.coaRcvd.AttrHandle);
784
785 // TODO: check port
786
787 ldrcCoa_parseCoa(&pMsg->msgData.coaRcvd, &pIdData);
788 status = ldrcCoa_findSession(&pIdData);
789 break;
790 default:
791 /*-----*/
792 LDRC_COA_ERROR("Unknown type %u", pMsg->type);
793 break;
794 }
795
796 ldrcCoa_freeMsg(pMsg);
797}
798
799/*
800 *==============================================================================
801 * ldrcCoa_Main
802 *==============================================================================
803 */
804PRIVATE void ldrcCoa_Main(void)
805{
806 tlrdcCoa_CoaMsg *pMsg;
807
808 /* Per-instance main work loop
809 * --------------------------*/
810 while (TRUE)
811 {
812 semTake(lrdcCoa_MainSem, WAIT_FOREVER);
813
814 while ((pMsg = TM_MSGQ_RECEIVE_PTR(&rlrdcCoa_MsgQ, tlrdcCoa_CoaMsg, link)))
815 {
816 if (ldrcCoa_InitTaskData() != SUCCESS)
817 {
818 ldrcCoa_freeMsg(pMsg);
819 break;
820 }
821
822 ldrcCoa_processMsg(pMsg);
823 }
824 }
825}
826
827/*
828 *==============================================================================
829 * lrdcCoa_RspCallBack
830 *==============================================================================
831 */
832PRIVATE void
833lrdcCoa_RspCallBack(tRadiusUserHandle userHandle,
834 tRadiusReqRef reference,
835 tRadiusAttributeHandle attributeHandle,
836 tRadiusCallBackRetCode retCode,
837 tUint32 PlcyData,
838 tUint32 serverIndex)
839{
840 LDRC_COA_EVENT("BNG COA: Unexpected call. retCode = %d, data = %p",
841 retCode, attributeHandle);
842}
843
844/*
845 *==============================================================================
846 * lrdcCoa_InitRadiusNgHandle
847 *==============================================================================
848 */
849PRIVATE tStatus lrdcCoa_InitRadiusNgHandle(void)
850{
851 ldrcCoa_radiusNgHandle = radiusNgSubscribe("radiusCpmBngCoa", lrdcCoa_RspCallBack);
852
853 if(ldrcCoa_radiusNgHandle == NULL)
854 {
855 LDRC_COA_ERROR("BNG COA: Cannot subscribe to radius_ng");
856 return FAIL;
857 }
858
859 return SUCCESS;
860}
861
862/*
863 *==============================================================================
864 * ldrcCoa_AsyncProcess
865 *==============================================================================
866 */
867PRIVATE tStatus ldrcCoa_AsyncProcess(tRadiusAttributeHandle AttrHandle,
868 tUint8 *pDiscMsg,
869 tUint16 msgLen,
870 tIpAnyAddr *pSrcAnyAddr,
871 tIpAnyAddr *pDstAnyAddr,
872 tUint16 srcPort,
873 tLrdcCoa_VrIfEntry *vrIfEntry)
874{
875 tlrdcCoa_CoaMsg *pMsg;
876
877 if ((pMsg = ldrcCoa_Calloc(1, sizeof(tlrdcCoa_CoaMsg))) == NULL)
878 {
879 return FAIL;
880 }
881
882 pMsg->type = LRDC_COA_MSG_INCOMING_COA;
883 pMsg->msgData.coaRcvd.AttrHandle = AttrHandle;
884 pMsg->msgData.coaRcvd.pDiscMsg = pDiscMsg;
885 pMsg->msgData.coaRcvd.msgLen = msgLen;
886 pMsg->msgData.coaRcvd.srcAnyAddr = *pSrcAnyAddr;
887 pMsg->msgData.coaRcvd.dstAnyAddr = *pDstAnyAddr;
888
889 pMsg->msgData.coaRcvd.vrIfEntry = *vrIfEntry;
890 pMsg->msgData.coaRcvd.srcPort = srcPort;
891
892 tmMsgQSend(&rlrdcCoa_MsgQ, &pMsg->link);
893 LDRC_COA_EVENT("BNG COA: COA dispatched to worker threads");
894
895 return OK;
896}
897
898/*
899 *==============================================================================
900 * lrdcCoa_CoaOrDiscMsgRcvd
901 *==============================================================================
902 */
903#define MSG_NOT_HANDLED FALSE;
904#define MSG_HANDLED TRUE;
905
906/*
907 *==============================================================================
908 * lrdcCoa_VrIfTreeCompFunc
909 *==============================================================================
910 */
911PRIVATE int lrdcCoa_VrIfTreeCompFunc(const char *p1, const char *p2)
912{
913 tLrdcCoa_VrIfEntry *pEntry1 = (tLrdcCoa_VrIfEntry*)p1;
914 tLrdcCoa_VrIfEntry *pEntry2 = (tLrdcCoa_VrIfEntry*)p2;
915
916 if (pEntry1->vRtrID > pEntry2->vRtrID)
917 return 1;
918 if (pEntry1->vRtrID < pEntry2->vRtrID)
919 return -1;
920
921 if (pEntry1->vRtrIfIndex > pEntry2->vRtrIfIndex)
922 return 1;
923 if (pEntry1->vRtrIfIndex < pEntry2->vRtrIfIndex)
924 return -1;
925
926 return 0;
927}
928
929/*
930 *==============================================================================
931 * lrdcCoa_VrIfTreeGetActive
932 *==============================================================================
933 * Get the currently active VrIfTable
934 */
935PRIVATE tAvlpTree *lrdcCoa_VrIfTreeGetActive(void)
936{
937 return pLrdcCoa_VrIfTable;
938}
939
940/*
941 *==============================================================================
942 * lrdcCoa_VrIfEntryCreate
943 *==============================================================================
944 */
945PRIVATE tLrdcCoa_VrIfEntry * lrdcCoa_VrIfEntryCreate(void)
946{
947 tLrdcCoa_VrIfEntry *pEntry;
948
949 pEntry = modMalloc(sizeof(tLrdcCoa_VrIfEntry), MOD_LRDC_COA);
950
951 if(pEntry)
952 {
953 totalNbrOfVrIfEntryMalloc++;
954 }
955 return pEntry;
956}
957
958/*
959 *==============================================================================
960 * lrdcCoa_VrIfEntryFree
961 *==============================================================================
962 * Free a new operation tree node
963 */
964PRIVATE tLrdcCoa_VrIfEntry * lrdcCoa_VrIfEntryFree(tLrdcCoa_VrIfEntry *pEntry)
965{
966 if (pEntry)
967 {
968 modFree(pEntry, MOD_LRDC_COA);
969 totalNbrOfVrIfEntryFrees++;
970 }
971 return NULL;
972}
973
974/*
975 *==============================================================================
976 * lrdcCoa_VrIfLocklessTableLookup
977 *==============================================================================
978 * There only exists one reader. He sets the AVL pointer to NULL while reading
979 * to notify the writer that he is handling the tree. If a new tree is written
980 * by a writer the pointer is not NULL anymore in the end, so the memory is freed.
981 * Otherwise the old value is written back.
982 */
983PRIVATE tStatus lrdcCoa_VrIfLocklessTableLookup(tLrdcCoa_VrIfEntry *pVrIfEntry)
984{
985 tStatus lookupStatus;
986 tAvlpTree *pOldTree;
987 tBoolean avlChanged;
988 tLrdcCoa_VrIfEntry *pValue;
989
990 /* Retrieve the pointer to the avl tree
991 * ------------------------------------
992 * The pointer is set to zero while retrieving it, indicating
993 * in this way that the avl tree is being accessed)
994 *
995 * when we retrieve a NULL ptr it means that no COAS interfaces
996 * have been configured
997 */
998 pOldTree = (tAvlpTree *)vxAtomicSetPtr(&pLrdcCoa_VrIfTable, NULL);
999
1000 if (pOldTree == NULL)
1001 {
1002 LDRC_COA_EVENT("BNG COA: OperVrIfTable does not exist.");
1003 return FAIL;
1004 }
1005
1006 /* Do the lookup
1007 * ------------*/
1008 lookupStatus = avlpLookup(pOldTree, (char *)pVrIfEntry, (void **)&pValue);
1009
1010 if (lookupStatus == AVLP_OK)
1011 {
1012 *pVrIfEntry = *pValue;
1013 LDRC_COA_EVENT("BNG COA: Lookup in OperVrIfTable: found OK (vRtrID=%d, vRtrIfIndex=%d, gwId=%d)",
1014 pValue->vRtrID, pValue->vRtrIfIndex, pValue->gwId);
1015 }
1016 else
1017 {
1018 LDRC_COA_EVENT("BNG COA: Lookup in OperVrIfTable failed for (vRtrID=%d, vRtrIfIndex=%d tree=%p)",
1019 pVrIfEntry->vRtrID, pVrIfEntry->vRtrIfIndex, pOldTree);
1020 }
1021
1022 /* Indicate that the tree is not longer being accessed
1023 *----------------------------------------------------
1024 * If a new pointer was put in place in the mean time
1025 * this means that our tree is no longer needed.
1026 */
1027 avlChanged = !vxCasPtr(&pLrdcCoa_VrIfTable, NULL, pOldTree);
1028
1029 if (avlChanged)
1030 {
1031 lrdcCoa_VrIfTreeFree(pOldTree);
1032 }
1033
1034 return lookupStatus;
1035}
1036
1037/*
1038 *==============================================================================
1039 * lrdcCoa_VrIfTreeFreeCallback
1040 *==============================================================================
1041 */
1042PRIVATE void lrdcCoa_VrIfTreeFreeCallback(void *pEntry)
1043{
1044 lrdcCoa_VrIfEntryFree((tLrdcCoa_VrIfEntry *)pEntry);
1045}
1046
1047/*
1048 *==============================================================================
1049 * lrdcCoa_CoaOrDiscMsgRcvd
1050 *==============================================================================
1051 */
1052PRIVATE tBoolean lrdcCoa_CoaOrDiscMsgRcvd(tRadiusUserHandle lrdcHandle,
1053 tRadiusAttributeHandle AttrHandle,
1054 tUint8 *pDiscMsg,
1055 int msgLen,
1056 tIpAnyAddr *srcAnyAddr,
1057 tIpAnyAddr *dstAnyAddr,
1058 tUint32 dscVrId,
1059 tUint16 srcPort)
1060{
1061 tLrdcCoa_VrIfEntry vrIfEntry = {.vRtrID = dscVrId};
1062 tTimNetAddr timNetAddr;
1063
1064 /* COA Handling activated?
1065 * ---------------------*/
1066 if (!get_runtime_feature_mg_cups_bng_coa())
1067 {
1068 return MSG_NOT_HANDLED;
1069 }
1070
1071 /* Discarding COA on stndby CPM
1072 * ---------------------------*/
1073 if (!(redAmIActive(RED_Module_Lte)))
1074 {
1075 LDRC_COA_EVENT("BNG COA: Discarding COA on stndby CPM");
1076 return MSG_NOT_HANDLED;
1077 }
1078
1079 /* Determine the interface we received the packet on
1080 * ------------------------------------------------*/
1081 IpAnyAddr2TimNetAddr(dstAnyAddr, &timNetAddr);
1082
1083 if (vrIfDbLookup(dscVrId, &timNetAddr, &vrIfEntry.vRtrIfIndex) != SUCCESS)
1084 {
1085 LDRC_COA_EVENT(
1086 "BNG COA: COA received on unrecognized interface: not handled by lrdcCoa");
1087 return MSG_NOT_HANDLED;
1088 }
1089
1090 /* Check if the interface is configured to handle lrdcCoa messages
1091 * --------------------------------------------------------------*/
1092 if (lrdcCoa_VrIfLocklessTableLookup(&vrIfEntry) != OK)
1093 {
1094 LDRC_COA_EVENT(
1095 "BNG COA: COA not recognized as belonging to lrdcCoa (ifIndex = %d, vrId = %d, gwId = %d)",
1096 vrIfEntry.vRtrIfIndex, dscVrId, vrIfEntry.gwId);
1097 return MSG_NOT_HANDLED;
1098 }
1099
1100 LDRC_COA_EVENT("BNG COA: COA received (ifIndex = %d, vrId = %d, gwId = %d)", vrIfEntry.vRtrIfIndex,
1101 dscVrId, vrIfEntry.gwId);
1102
1103 /* Pass the COA in a message to the COA processing tasks
1104 * ----------------------------------------------------*/
1105 if (ldrcCoa_AsyncProcess(AttrHandle, pDiscMsg, msgLen, srcAnyAddr, dstAnyAddr,
1106 srcPort, &vrIfEntry) != SUCCESS)
1107 {
1108 LDRC_COA_EVENT(
1109 "BNG COA: Could not pass COA to lrdcCoa tasks (ifIndex = %d, vrId = %d, gwId = %d)",
1110 vrIfEntry.vRtrIfIndex, dscVrId, vrIfEntry.gwId);
1111 return MSG_NOT_HANDLED;
1112 }
1113
1114 return MSG_HANDLED;
1115}
1116
1117/*
1118 *==============================================================================
1119 * lrdcCoa_RegRadiusNgFns
1120 *==============================================================================
1121 */
1122PRIVATE tStatus lrdcCoa_RegRadiusNgFns(void)
1123{
1124 tStatus status;
1125
1126 status = radiusNgAddUserFns(
1127 ldrcCoa_radiusNgHandle,
1128 RADIUS_COA_CLNT_BNG_COA, // DISCON/COA clientID
1129 NULL, // radius server OPstat change notify
1130 lrdcCoa_CoaOrDiscMsgRcvd, // disc-notify only on CPM
1131 NULL); // acct-on msg is only on CPM
1132
1133 if(status != OK)
1134 {
1135 LDRC_COA_ERROR("Cannot register functions to radius_ng");
1136 return FAIL;
1137 }
1138 return SUCCESS;
1139}
1140
1141/*-------------------------------------------------------------------------------------*/
1142/* PUBLIC Functions */
1143/*-------------------------------------------------------------------------------------*/
1144
1145/*
1146 *==============================================================================
1147 * rdcCoa_VrIfTreeCreate
1148 *==============================================================================
1149 */
1150PUBLIC tAvlpTree * lrdcCoa_VrIfTreeCreate(void)
1151{
1152 tAvlpTree *pTree;
1153
1154 pTree = avlpNewTree(lrdcCoa_VrIfTreeCompFunc, MOD_LRDC_COA);
1155
1156 /* Disable the semaphore checking since we use a custom RCU mechanism */
1157 avlpDisableLockChecks(pTree);
1158
1159 if (pTree)
1160 {
1161 nbrOfOperTreesCreated++;
1162 }
1163
1164 LDRC_COA_EVENT("BNG COA: Create new OperVrIfTree (%p) : %s",
1165 pTree,
1166 ((pTree)? "SUCCESS" : "FAILED"));
1167
1168 return pTree;
1169}
1170
1171/*
1172 *==============================================================================
1173 * lrdcCoa_VrIfTreeFree
1174 *==============================================================================
1175 */
1176PUBLIC void lrdcCoa_VrIfTreeFree(tAvlpTree *pTree)
1177{
1178 if (pTree)
1179 {
1180 LDRC_COA_EVENT("BNG COA: Remove OperVrIfTree : %p", pTree);
1181 nbrOfOperTreesFreed++;
1182
1183 avlpFreeTree(pTree, NULL, lrdcCoa_VrIfTreeFreeCallback);
1184 pTree = NULL;
1185 }
1186}
1187
1188/*
1189 *==============================================================================
1190 * lrdcCoa_VrIfTableInsertEntry
1191 *==============================================================================
1192 */
1193PUBLIC tLrdcCoa_VrIfEntry *lrdcCoa_VrIfTableInsertEntry(tAvlpTree *pTree,
1194 tLrdcCoa_VrIfEntry *pEntry)
1195{
1196 tStatus status;
1197 tLrdcCoa_VrIfEntry *pEntryNew;
1198
1199 // Allocate new entry
1200 pEntryNew = lrdcCoa_VrIfEntryCreate();
1201 CHECK_ERROR(!pEntryNew, RET, "BNG COA: Failed to allocate memory to store a CoA "
1202 "Interface in tree %p (vRtrID=%d, vRtrIfIndex=%d, gwId=%d)",
1203 pTree, pEntry->vRtrID, pEntry->vRtrIfIndex, pEntry->gwId )
1204
1205 // Initialize the entry
1206 *pEntryNew = *pEntry;
1207
1208 // Insert to the tree
1209 status = avlpInsert(pTree, (char *)pEntryNew, pEntryNew);
1210 CHECK_ERROR(status != AVLP_OK, ERR_FREE_PENTRY,
1211 "BNG COA: Failed to add entry (vRtrID=%d, vRtrIfIndex=%d, gwId=%d) to operVrIfTable %p",
1212 pEntry->vRtrID, pEntry->vRtrIfIndex, pEntry->gwId, pTree);
1213
1214 LDRC_COA_EVENT("BNG COA: Added entry (vRtrID=%d, vRtrIfIndex=%d, gwId=%d) to operVrIfTable %p",
1215 pEntry->vRtrID, pEntry->vRtrIfIndex, pEntry->gwId, pTree);
1216
1217 goto RET;
1218
1219ERR_FREE_PENTRY:
1220 pEntryNew = lrdcCoa_VrIfEntryFree(pEntryNew);
1221
1222RET:
1223 return pEntryNew;
1224}
1225
1226/*
1227 *==============================================================================
1228 * lrdcCoa_VrIfTreeReplace
1229 *==============================================================================
1230 * Free a new operation tree node
1231 */
1232PUBLIC void lrdcCoa_VrIfTreeReplace(tAvlpTree *pNewTree)
1233{
1234 tAvlpTree *pOldTree;
1235 tUint32 sizeNewTree = avlpCount(pNewTree);
1236
1237 /* Replace old operation tree with new one
1238 * --------------------------------------*/
1239 pOldTree = (tAvlpTree *)vxAtomicSetPtr(&pLrdcCoa_VrIfTable, pNewTree);
1240
1241 LDRC_COA_EVENT("BNG COA: Replace tree %p (%d entries) with tree %p (%d entries)",
1242 pOldTree, avlpCount(pOldTree), pNewTree, sizeNewTree);
1243
1244 nbrOfOperationalTreeSwaps++;
1245
1246 /* Free the old tree if it is not being used by the reader
1247 * -------------------------------------------------------
1248 * Otherwise the reader is responsible to free it.
1249 */
1250 if (pOldTree)
1251 {
1252 LDRC_COA_EVENT("BNG COA: Freeing old tree during tree replace action.");
1253 lrdcCoa_VrIfTreeFree(pOldTree);
1254 }
1255}
1256
1257/*
1258 *==============================================================================
1259 * lrdcCoa_VrIfTreeDeleteEntry
1260 *==============================================================================
1261 */
1262PUBLIC void lrdcCoa_VrIfTreeDeleteEntry(tAvlpTree *pTree, tLrdcCoa_VrIfEntry *pEntry)
1263{
1264 tStatus status;
1265 tLrdcCoa_VrIfEntry *pEntryDel;
1266
1267 status = avlpDelete(pTree,
1268 (char *)pEntry, NULL, (void **)&pEntryDel);
1269
1270 CHECK_ERROR(status != AVLP_OK, RET,
1271 "BNG COA: Deleting CoaIf entry vRtrID=%d, vRtrIfIndex=%d, gwId=%d)"
1272 "from operVrIfTable %p failed unexpectedly.",
1273 pEntry->vRtrID, pEntry->vRtrIfIndex, pEntry->gwId, pTree);
1274
1275 pEntryDel = lrdcCoa_VrIfEntryFree(pEntryDel);
1276
1277 LDRC_COA_EVENT("BNG COA: Removed entry (vRtrID=%d, vRtrIfIndex=%d, gwId=%d) from operVrIfTable %p",
1278 pEntry->vRtrID, pEntry->vRtrIfIndex, pEntry->gwId, pTree);
1279
1280RET:
1281 return;
1282}
1283
1284/*
1285 *==============================================================================
1286 * lrdcCoa_Init
1287 *==============================================================================
1288 */
1289PUBLIC void lrdcCoa_Init(void)
1290{
1291 /* Create the memory manager
1292 * ------------------------*/
1293 rlrdcCoa_DfragMgr = dfrag_mgr_create(MOD_LRDC_COA);
1294 ASSERT(rlrdcCoa_DfragMgr);
1295
1296 /* Create semaphores
1297 * ----------------*/
1298 lrdcCoa_MainSem = semSCreateX(SEM_Q_PRIORITY, "lrdcCoa_MainSem", 0);
1299 ASSERT(lrdcCoa_MainSem);
1300
1301 /* Create RX queue
1302 * --------------*/
1303 tmMsgQInit(&rlrdcCoa_MsgQ, lrdcCoa_MainSem);
1304
1305 /* Create COA If lookup table
1306 * --------------------------
1307 * The table will be populated while adding rows to the mnxMobPdnBngCoaIfTable
1308 */
1309 pLrdcCoa_VrIfTable = lrdcCoa_VrIfTreeCreate();
1310 ASSERT(pLrdcCoa_VrIfTable);
1311}
1312
1313/*
1314 *==============================================================================
1315 * lrdcCoa_Start
1316 *==============================================================================
1317 */
1318PUBLIC tStatus lrdcCoa_Start(void)
1319{
1320 int i;
1321 tUint32 numTasks = ldrcCoa_getNumTasks();
1322 char taskName[64];
1323
1324 if (!runtime_feature_smf_fixed_access)
1325 {
1326 return OK;
1327 }
1328
1329 /* Spawn a set of tasks
1330 * -------------------*/
1331 for (i = 0; i < numTasks; i++)
1332 {
1333 snprintf(taskName, sizeof(taskName), "%s-%u", LRDC_COA_TASK_NAME, i);
1334
1335 if (taskSpawnX(MOD_LRDC_COA, taskName, LRDC_COA_TASK_PRIORITY, 0,
1336 LARGE_STACK, (FUNCPTR)ldrcCoa_Main,
1337 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == TASK_ID_ERROR)
1338 {
1339 ASSERT(0);
1340 }
1341 }
1342 LDRC_COA_EVENT("BNG COA: Spawned %d ldrc BNG COA Tasks", numTasks);
1343
1344 /* Register this application to the Radius backEnd
1345 * ----------------------------------------------*/
1346 // Subscribe to radius-ng and register notify to radius-ng
1347 if(lrdcCoa_InitRadiusNgHandle() != SUCCESS)
1348 {
1349 LDRC_COA_ERROR("BNG COA: Radius-NG BNG COA subscribe failure");
1350 return ERROR;
1351 }
1352
1353 //Register (to add) a set of LRDC COA specific functions to radius_ng
1354 if (lrdcCoa_RegRadiusNgFns() != SUCCESS)
1355 {
1356 LDRC_COA_ERROR("BNG COA: Radius-NG BNG COA specific functions to Radius-NG failure");
1357 return ERROR;
1358 }
1359
1360 return OK;
1361}
1362
1363/*-------------------------------------------------------------------------------------*/
1364/* debug/shell Functions */
1365/*-------------------------------------------------------------------------------------*/
1366/*
1367 *==============================================================================
1368 * lrdcCoa_operVrIfTreeStats
1369 *==============================================================================
1370 */
1371PUBLIC void lrdcCoa_operVrIfTreeStats(tBoolean reset)
1372{
1373 printf("\n");
1374 printf("\n totalNumber of entries allocated : %d ", totalNbrOfVrIfEntryMalloc);
1375 printf("\n totalNumber of entries freed : %d ", totalNbrOfVrIfEntryFrees);
1376 printf("\n totalNumber of operational tree creates : %d ", nbrOfOperTreesCreated);
1377 printf("\n totalNumber of operational tree deletes : %d ", nbrOfOperTreesFreed);
1378 printf("\n totalNumber of operational tree swaps : %d ", nbrOfOperationalTreeSwaps);
1379 printf("\n totalNumber of COA msg sent to private thread : %d ", rlrdcCoa_NumMsgs);
1380 printf("\n");
1381
1382 if (reset)
1383 {
1384 totalNbrOfVrIfEntryMalloc = 0;
1385 totalNbrOfVrIfEntryFrees = 0;
1386 nbrOfOperTreesCreated = 0;
1387 nbrOfOperTreesFreed = 0;
1388 nbrOfOperationalTreeSwaps = 0;
1389 rlrdcCoa_NumMsgs = 0;
1390 }
1391}
1392
1393/*
1394 *==============================================================================
1395 * lrdcCoa_operVrIfTreeDump
1396 *==============================================================================
1397 */
1398PUBLIC void lrdcCoa_operVrIfTreeDump(void)
1399{
1400 tLrdcCoa_VrIfEntry *pEntry;
1401 tStatus status;
1402 tUint32 nbrEntries = 0;
1403
1404 if (!pLrdcCoa_VrIfTable)
1405 {
1406 printf("\n no operational tree found \n");
1407 return;
1408 }
1409
1410 status = avlpFirst(pLrdcCoa_VrIfTable, NULL, (void **) &pEntry);
1411
1412 if (status != AVLP_OK)
1413 {
1414 printf("\n operational tree is empty\n");
1415 return;
1416 }
1417 printf("\n------------------------------------------\n");
1418
1419 while (status == AVLP_OK)
1420 {
1421 printf("\n Entry: vRtrID = %d , vRtrIfIndex = %d gwId = %d",
1422 pEntry->vRtrID,
1423 pEntry->vRtrIfIndex,
1424 pEntry->gwId);
1425
1426 status = avlpNext(pLrdcCoa_VrIfTable,
1427 (char *)pEntry, NULL, (void **) &pEntry);
1428 nbrEntries++;
1429 }
1430
1431 printf("\nTotal: %d Entries(s).", nbrEntries);
1432 printf("\n------------------------------------------\n");
1433}
1434
1435/*
1436 *==============================================================================
1437 * lrdcCoa_operVrIfTreeStats
1438 *==============================================================================
1439 */
1440PUBLIC void lrdcCoa_PacketStats(tBoolean reset)
1441{
1442 printf("\n");
1443 printf("\n totalNumber of CoAs received : %d ", coaPctsReceived);
1444 printf("\n totalNumber of CoAs rejected Size : %d ", coaPctsRejectedSize);
1445 printf("\n totalNumber of CoAs rejected authenticator : %d ", coaPctsRejectedAuth);
1446 printf("\n totalNumber of CoAs rejected malformed attr : %d ", coaPctsRejectedAttr);
1447 printf("\n");
1448
1449 if (reset)
1450 {
1451 coaPctsReceived = 0;
1452 coaPctsRejectedSize = 0;
1453 coaPctsRejectedAuth = 0;
1454 coaPctsRejectedAttr = 0;
1455 }
1456}
1457
1458PUBLIC void lrdcCoa_testParser(tBoolean reset)
1459{
1460 tlrdcCoa_idData idData = {};
1461 int status;
1462
1463 tUint8 packet[][5] = {
1464 {44, 5, 1,2,3},
1465 {44, 5, 1,2,3},
1466 {44, 2, 1,2,3}
1467 };
1468 for (int i = 0; i < sizeof(packet); i++) {
1469 status = ldrcCoa_parseAttrs(packet[i],
1470 sizeof(packet[i]),
1471 &idData,
1472 ldrcCoa_parseAttr);
1473 printf("%d", status);
1474 printf("%x %x %x",
1475 idData.acctSessionId->bytes[0],
1476 idData.acctSessionId->bytes[1],
1477 idData.acctSessionId->bytes[2]);
1478 }
1479
1480 tUint8 packet2[] = {26, 11, 0, 0,0x19,0x7f, 100, 1,2,3,4};
1481 status = ldrcCoa_parseAttrs(packet2,
1482 sizeof(packet2),
1483 &idData,
1484 ldrcCoa_parseAttr);
1485 printf("status=%d, servId=%d",status, idData.timetraServId);
1486
1487 // Empty attribute
1488 tUint8 packet3[] = {26, 2};
1489 status = ldrcCoa_parseAttrs(packet3,
1490 sizeof(packet3),
1491 &idData,
1492 ldrcCoa_parseAttr);
1493 printf("Empty attrubute status=%d", status);
1494}