1 // SoftEther VPN Source Code - Developer Edition Master Branch
2 // Cedar Communication Module
3 
4 
5 // Cedar.c
6 // Cedar Communication Module
7 
8 #include "Cedar.h"
9 
10 #include "Admin.h"
11 #include "Bridge.h"
12 #include "Connection.h"
13 #include "Layer3.h"
14 #include "Link.h"
15 #include "Listener.h"
16 #include "Protocol.h"
17 #include "Sam.h"
18 #include "Server.h"
19 #include "Session.h"
20 #include "VLanWin32.h"
21 #include "WebUI.h"
22 
23 #include "Mayaqua/Cfg.h"
24 #include "Mayaqua/Encrypt.h"
25 #include "Mayaqua/FileIO.h"
26 #include "Mayaqua/HTTP.h"
27 #include "Mayaqua/Mayaqua.h"
28 #include "Mayaqua/Memory.h"
29 #include "Mayaqua/Microsoft.h"
30 #include "Mayaqua/Object.h"
31 #include "Mayaqua/Str.h"
32 #include "Mayaqua/Table.h"
33 #include "Mayaqua/Tick64.h"
34 #include "Mayaqua/Win32.h"
35 
36 #include <sodium.h>
37 
38 static UINT init_cedar_counter = 0;
39 static REF *cedar_log_ref = NULL;
40 static LOG *cedar_log;
41 
42 // Check whether there is any EAP-enabled RADIUS configuration
CedarIsThereAnyEapEnabledRadiusConfig(CEDAR * c)43 bool CedarIsThereAnyEapEnabledRadiusConfig(CEDAR *c)
44 {
45 	bool ret = false;
46 	UINT i;
47 	if (c == NULL)
48 	{
49 		return false;
50 	}
51 
52 	LockHubList(c);
53 	{
54 		for (i = 0;i < LIST_NUM(c->HubList);i++)
55 		{
56 			HUB *hub = LIST_DATA(c->HubList, i);
57 
58 			if (hub->RadiusConvertAllMsChapv2AuthRequestToEap)
59 			{
60 				ret = true;
61 				break;
62 			}
63 		}
64 	}
65 	UnlockHubList(c);
66 
67 	return ret;
68 }
69 
70 // Get build date of current code
GetCurrentBuildDate()71 UINT64 GetCurrentBuildDate()
72 {
73 	SYSTEMTIME st;
74 
75 	Zero(&st, sizeof(st));
76 
77 	st.wYear = BUILD_DATE_Y;
78 	st.wMonth = BUILD_DATE_M;
79 	st.wDay = BUILD_DATE_D;
80 	st.wHour = BUILD_DATE_HO;
81 	st.wMinute = BUILD_DATE_MI;
82 	st.wSecond = BUILD_DATE_SE;
83 
84 	return SystemToUINT64(&st);
85 }
86 
87 // Check current windows version is supported
IsSupportedWinVer(RPC_WINVER * v)88 bool IsSupportedWinVer(RPC_WINVER *v)
89 {
90 	// Validate arguments
91 	if (v == NULL)
92 	{
93 		return false;
94 	}
95 
96 	if (v->IsWindows == false)
97 	{
98 		return true;
99 	}
100 
101 	if (v->IsNT == false)
102 	{
103 		return true;
104 	}
105 
106 	if (v->IsBeta)
107 	{
108 		return true;
109 	}
110 
111 	if (v->VerMajor <= 4)
112 	{
113 		// Windows NT
114 		return true;
115 	}
116 
117 	if (v->VerMajor == 5 && v->VerMinor == 0)
118 	{
119 		// Windows 2000
120 		if (v->ServicePack <= 4)
121 		{
122 			// SP4 or earlier
123 			return true;
124 		}
125 	}
126 
127 	if (v->VerMajor == 5 && v->VerMinor == 1)
128 	{
129 		// Windows XP x86
130 		if (v->ServicePack <= 3)
131 		{
132 			// SP3 or earlier
133 			return true;
134 		}
135 	}
136 
137 	if (v->VerMajor == 5 && v->VerMinor == 2)
138 	{
139 		// Windows XP x64, Windows Server 2003
140 		if (v->ServicePack <= 2)
141 		{
142 			// SP2 or earlier
143 			return true;
144 		}
145 	}
146 
147 	if (v->VerMajor == 6 && v->VerMinor == 0)
148 	{
149 		// Windows Vista, Server 2008
150 		if (v->ServicePack <= 2)
151 		{
152 			// SP2 or earlier
153 			return true;
154 		}
155 	}
156 
157 	if (v->VerMajor == 6 && v->VerMinor == 1)
158 	{
159 		// Windows 7, Server 2008 R2
160 		if (v->ServicePack <= 1)
161 		{
162 			// SP1 or earlier
163 			return true;
164 		}
165 	}
166 
167 	if (v->VerMajor == 6 && v->VerMinor == 2)
168 	{
169 		// Windows 8, Server 2012
170 		if (v->ServicePack <= 0)
171 		{
172 			// SP0 only
173 			return true;
174 		}
175 	}
176 
177 	if (v->VerMajor == 6 && v->VerMinor == 3)
178 	{
179 		// Windows 8.1, Server 2012 R2
180 		if (v->ServicePack <= 0)
181 		{
182 			// SP0 only
183 			return true;
184 		}
185 	}
186 
187 	if ((v->VerMajor == 6 && v->VerMinor == 4) || (v->VerMajor == 10 && v->VerMinor == 0))
188 	{
189 		// Windows 10 or Windows Server 2016
190 		if (v->ServicePack <= 0)
191 		{
192 			// SP0 only
193 			return true;
194 		}
195 	}
196 
197 	return false;
198 }
199 
200 // Get version of Windows
GetWinVer(RPC_WINVER * v)201 void GetWinVer(RPC_WINVER *v)
202 {
203 	// Validate arguments
204 	if (v == NULL)
205 	{
206 		return;
207 	}
208 
209 #ifdef	OS_WIN32
210 	Win32GetWinVer(v);
211 #else	// OS_WIN32
212 	Zero(v, sizeof(RPC_WINVER));
213 	StrCpy(v->Title, sizeof(v->Title), GetOsInfo()->OsProductName);
214 #endif	// OS_WIN32
215 }
216 
217 // Close tiny log
FreeTinyLog(TINY_LOG * t)218 void FreeTinyLog(TINY_LOG *t)
219 {
220 	// Validate arguments
221 	if (t == NULL)
222 	{
223 		return;
224 	}
225 
226 	FileClose(t->io);
227 	DeleteLock(t->Lock);
228 	Free(t);
229 }
230 
231 // Write to tiny log
WriteTinyLog(TINY_LOG * t,char * str)232 void WriteTinyLog(TINY_LOG *t, char *str)
233 {
234 	BUF *b;
235 	char dt[MAX_PATH];
236 	// Validate arguments
237 	if (t == NULL)
238 	{
239 		return;
240 	}
241 
242 	GetDateTimeStrMilli64(dt, sizeof(dt), LocalTime64());
243 	StrCat(dt, sizeof(dt), ": ");
244 
245 	b = NewBuf();
246 
247 	WriteBuf(b, dt, StrLen(dt));
248 	WriteBuf(b, str, StrLen(str));
249 	WriteBuf(b, "\r\n", 2);
250 
251 	Lock(t->Lock);
252 	{
253 		FileWrite(t->io, b->Buf, b->Size);
254 		//FileFlush(t->io);
255 	}
256 	Unlock(t->Lock);
257 
258 	FreeBuf(b);
259 }
260 
261 // Initialize tiny log
NewTinyLog()262 TINY_LOG *NewTinyLog()
263 {
264 	char name[MAX_PATH];
265 	SYSTEMTIME st;
266 	TINY_LOG *t;
267 
268 	LocalTime(&st);
269 
270 	MakeDir(TINY_LOG_DIRNAME);
271 
272 	Format(name, sizeof(name), TINY_LOG_FILENAME,
273 		st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
274 
275 	t = ZeroMalloc(sizeof(TINY_LOG));
276 
277 	StrCpy(t->FileName, sizeof(t->FileName), name);
278 	t->io = FileCreate(name);
279 	t->Lock = NewLock();
280 
281 	return t;
282 }
283 
284 // Compare entries of No-SSL connection list
CompareNoSslList(void * p1,void * p2)285 int CompareNoSslList(void *p1, void *p2)
286 {
287 	NON_SSL *n1, *n2;
288 	if (p1 == NULL || p2 == NULL)
289 	{
290 		return 0;
291 	}
292 	n1 = *(NON_SSL **)p1;
293 	n2 = *(NON_SSL **)p2;
294 	if (n1 == NULL || n2 == NULL)
295 	{
296 		return 0;
297 	}
298 	return CmpIpAddr(&n1->IpAddress, &n2->IpAddress);
299 }
300 
301 // Decrement connection count of Non-SSL connection list entry
DecrementNoSsl(CEDAR * c,IP * ip,UINT num_dec)302 void DecrementNoSsl(CEDAR *c, IP *ip, UINT num_dec)
303 {
304 	// Validate arguments
305 	if (c == NULL || ip == NULL)
306 	{
307 		return;
308 	}
309 
310 	LockList(c->NonSslList);
311 	{
312 		NON_SSL *n = SearchNoSslList(c, ip);
313 
314 		if (n != NULL)
315 		{
316 			if (n->Count >= num_dec)
317 			{
318 				n->Count -= num_dec;
319 			}
320 		}
321 	}
322 	UnlockList(c->NonSslList);
323 }
324 
325 // Add new entry to Non-SSL connection list
AddNoSsl(CEDAR * c,IP * ip)326 bool AddNoSsl(CEDAR *c, IP *ip)
327 {
328 	NON_SSL *n;
329 	bool ret = true;
330 	// Validate arguments
331 	if (c == NULL || ip == NULL)
332 	{
333 		return true;
334 	}
335 
336 	LockList(c->NonSslList);
337 	{
338 		DeleteOldNoSsl(c);
339 
340 		n = SearchNoSslList(c, ip);
341 
342 		if (n == NULL)
343 		{
344 			n = ZeroMalloc(sizeof(NON_SSL));
345 			Copy(&n->IpAddress, ip, sizeof(IP));
346 			n->Count = 0;
347 
348 			Add(c->NonSslList, n);
349 		}
350 
351 		n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES;
352 
353 		n->Count++;
354 
355 		if (n->Count > NON_SSL_MIN_COUNT)
356 		{
357 			ret = false;
358 		}
359 	}
360 	UnlockList(c->NonSslList);
361 
362 	return ret;
363 }
364 
365 // Delete old entries in Non-SSL connection list
DeleteOldNoSsl(CEDAR * c)366 void DeleteOldNoSsl(CEDAR *c)
367 {
368 	UINT i;
369 	LIST *o;
370 	// Validate arguments
371 	if (c == NULL)
372 	{
373 		return;
374 	}
375 
376 	o = NewListFast(NULL);
377 
378 	for (i = 0;i < LIST_NUM(c->NonSslList);i++)
379 	{
380 		NON_SSL *n = LIST_DATA(c->NonSslList, i);
381 
382 		if (n->EntryExpires <= Tick64())
383 		{
384 			Add(o, n);
385 		}
386 	}
387 
388 	for (i = 0;i < LIST_NUM(o);i++)
389 	{
390 		NON_SSL *n = LIST_DATA(o, i);
391 
392 		Delete(c->NonSslList, n);
393 		Free(n);
394 	}
395 
396 	ReleaseList(o);
397 }
398 
399 // Search entry in Non-SSL connection list
SearchNoSslList(CEDAR * c,IP * ip)400 NON_SSL *SearchNoSslList(CEDAR *c, IP *ip)
401 {
402 	NON_SSL *n, t;
403 	// Validate arguments
404 	if (c == NULL || ip == NULL)
405 	{
406 		return NULL;
407 	}
408 
409 	Zero(&t, sizeof(t));
410 	Copy(&t.IpAddress, ip, sizeof(IP));
411 
412 	n = Search(c->NonSslList, &t);
413 
414 	if (n == NULL)
415 	{
416 		return NULL;
417 	}
418 
419 	return n;
420 }
421 
422 // Initialize Non-SSL connection list
InitNoSslList(CEDAR * c)423 void InitNoSslList(CEDAR *c)
424 {
425 	// Validate arguments
426 	if (c == NULL)
427 	{
428 		return;
429 	}
430 
431 	c->NonSslList = NewList(CompareNoSslList);
432 }
433 
434 // Free Non-SSL connection list
FreeNoSslList(CEDAR * c)435 void FreeNoSslList(CEDAR *c)
436 {
437 	UINT i;
438 	// Validate arguments
439 	if (c == NULL)
440 	{
441 		return;
442 	}
443 
444 	for (i = 0;i < LIST_NUM(c->NonSslList);i++)
445 	{
446 		NON_SSL *n = LIST_DATA(c->NonSslList, i);
447 
448 		Free(n);
449 	}
450 
451 	ReleaseList(c->NonSslList);
452 	c->NonSslList = NULL;
453 }
454 
455 // Start Cedar log
StartCedarLog()456 void StartCedarLog()
457 {
458 	if (cedar_log_ref == NULL)
459 	{
460 		cedar_log_ref = NewRef();
461 	}
462 	else
463 	{
464 		AddRef(cedar_log_ref);
465 	}
466 
467 	cedar_log = NewLog("debug_log", "debug", LOG_SWITCH_DAY);
468 }
469 
470 // Stop Cedar log
StopCedarLog()471 void StopCedarLog()
472 {
473 	if (cedar_log_ref == NULL)
474 	{
475 		return;
476 	}
477 
478 	if (Release(cedar_log_ref) == 0)
479 	{
480 		FreeLog(cedar_log);
481 		cedar_log = NULL;
482 		cedar_log_ref = NULL;
483 	}
484 }
485 
486 
487 // Get sum of traffic data size
GetTrafficPacketSize(TRAFFIC * t)488 UINT64 GetTrafficPacketSize(TRAFFIC *t)
489 {
490 	// Validate arguments
491 	if (t == NULL)
492 	{
493 		return 0;
494 	}
495 
496 	return t->Recv.BroadcastBytes + t->Recv.UnicastBytes +
497 		t->Send.BroadcastBytes + t->Send.UnicastBytes;
498 }
499 
500 // Get sum of the number of packets in traffic
GetTrafficPacketNum(TRAFFIC * t)501 UINT64 GetTrafficPacketNum(TRAFFIC *t)
502 {
503 	// Validate arguments
504 	if (t == NULL)
505 	{
506 		return 0;
507 	}
508 
509 	return t->Recv.BroadcastCount + t->Recv.UnicastCount +
510 		t->Send.BroadcastCount + t->Send.UnicastCount;
511 }
512 
513 // Check whether the certificate is signed by CA which is trusted by the hub
CheckSignatureByCaLinkMode(SESSION * s,X * x)514 bool CheckSignatureByCaLinkMode(SESSION *s, X *x)
515 {
516 	LINK *k;
517 	HUB *h;
518 	bool ret = false;
519 	// Validate arguments
520 	if (s == NULL || x == NULL)
521 	{
522 		return false;
523 	}
524 
525 	if (s->LinkModeClient == false || (k = s->Link) == NULL)
526 	{
527 		return false;
528 	}
529 
530 	h = k->Hub;
531 
532 	if (h->HubDb != NULL)
533 	{
534 		LockList(h->HubDb->RootCertList);
535 		{
536 			X *root_cert;
537 			root_cert = GetIssuerFromList(h->HubDb->RootCertList, x);
538 			if (root_cert != NULL)
539 			{
540 				ret = true;
541 			}
542 		}
543 		UnlockList(h->HubDb->RootCertList);
544 	}
545 
546 	return ret;
547 }
548 
549 // Check whether the certificate is signed by CA which is trusted by Cedar
CheckSignatureByCa(CEDAR * cedar,X * x)550 bool CheckSignatureByCa(CEDAR *cedar, X *x)
551 {
552 	X *ca;
553 	// Validate arguments
554 	if (cedar == NULL || x == NULL)
555 	{
556 		return false;
557 	}
558 
559 	// Get the CA which signed the certificate
560 	ca = FindCaSignedX(cedar->CaList, x);
561 	if (ca == NULL)
562 	{
563 		// Not found
564 		return false;
565 	}
566 
567 	// Found
568 	FreeX(ca);
569 	return true;
570 }
571 
572 // Get the CA which signed the certificate
FindCaSignedX(LIST * o,X * x)573 X *FindCaSignedX(LIST *o, X *x)
574 {
575 	X *ret;
576 	// Validate arguments
577 	if (o == NULL || x == NULL)
578 	{
579 		return NULL;
580 	}
581 
582 	ret = NULL;
583 
584 	LockList(o);
585 	{
586 		UINT i;
587 		for (i = 0;i < LIST_NUM(o);i++)
588 		{
589 			X *ca = LIST_DATA(o, i);
590 			if (CheckXDateNow(ca))
591 			{
592 				if (CompareName(ca->subject_name, x->issuer_name))
593 				{
594 					K *k = GetKFromX(ca);
595 					if (k != NULL)
596 					{
597 						if (CheckSignature(x, k))
598 						{
599 							ret = CloneX(ca);
600 						}
601 						FreeK(k);
602 					}
603 				}
604 				else if (CompareX(ca, x))
605 				{
606 					ret = CloneX(ca);
607 				}
608 			}
609 
610 			if (ret != NULL)
611 			{
612 				break;
613 			}
614 		}
615 	}
616 	UnlockList(o);
617 
618 	return ret;
619 }
620 
621 // Delete trusted CA from Cedar
DeleteCa(CEDAR * cedar,UINT ptr)622 bool DeleteCa(CEDAR *cedar, UINT ptr)
623 {
624 	bool b = false;
625 	// Validate arguments
626 	if (cedar == NULL || ptr == 0)
627 	{
628 		return false;
629 	}
630 
631 	LockList(cedar->CaList);
632 	{
633 		UINT i;
634 
635 		for (i = 0;i < LIST_NUM(cedar->CaList);i++)
636 		{
637 			X *x = LIST_DATA(cedar->CaList, i);
638 
639 			if (POINTER_TO_KEY(x) == ptr)
640 			{
641 				Delete(cedar->CaList, x);
642 				FreeX(x);
643 
644 				b = true;
645 
646 				break;
647 			}
648 		}
649 	}
650 	UnlockList(cedar->CaList);
651 
652 	return b;
653 }
654 
655 // Add trusted CA to Cedar
AddCa(CEDAR * cedar,X * x)656 void AddCa(CEDAR *cedar, X *x)
657 {
658 	// Validate arguments
659 	if (cedar == NULL || x == NULL)
660 	{
661 		return;
662 	}
663 
664 	LockList(cedar->CaList);
665 	{
666 		UINT i;
667 		bool ok = true;
668 
669 		for (i = 0;i < LIST_NUM(cedar->CaList);i++)
670 		{
671 			X *exist_x = LIST_DATA(cedar->CaList, i);
672 			if (CompareX(exist_x, x))
673 			{
674 				ok = false;
675 				break;
676 			}
677 		}
678 
679 		if (ok)
680 		{
681 			Insert(cedar->CaList, CloneX(x));
682 		}
683 	}
684 	UnlockList(cedar->CaList);
685 }
686 
687 // Delete connection from Cedar
DelConnection(CEDAR * cedar,CONNECTION * c)688 void DelConnection(CEDAR *cedar, CONNECTION *c)
689 {
690 	// Validate arguments
691 	if (cedar == NULL || c == NULL)
692 	{
693 		return;
694 	}
695 
696 	LockList(cedar->ConnectionList);
697 	{
698 		Debug("Connection %s Deleted from Cedar.\n", c->Name);
699 		if (Delete(cedar->ConnectionList, c))
700 		{
701 			ReleaseConnection(c);
702 		}
703 	}
704 	UnlockList(cedar->ConnectionList);
705 }
706 
707 // Add connection to Cedar
AddConnection(CEDAR * cedar,CONNECTION * c)708 void AddConnection(CEDAR *cedar, CONNECTION *c)
709 {
710 	char tmp[MAX_SIZE];
711 	UINT i;
712 	// Validate arguments
713 	if (cedar == NULL || c == NULL)
714 	{
715 		return;
716 	}
717 
718 	// Determine the name of the connection
719 	i = Inc(cedar->ConnectionIncrement);
720 	Format(tmp, sizeof(tmp), "CID-%u", i);
721 
722 
723 	Lock(c->lock);
724 	{
725 		Free(c->Name);
726 		c->Name = CopyStr(tmp);
727 	}
728 	Unlock(c->lock);
729 
730 	LockList(cedar->ConnectionList);
731 	{
732 		Add(cedar->ConnectionList, c);
733 		AddRef(c->ref);
734 		Debug("Connection %s Inserted to Cedar.\n", c->Name);
735 	}
736 	UnlockList(cedar->ConnectionList);
737 }
738 
739 // Stop all connections
StopAllConnection(CEDAR * c)740 void StopAllConnection(CEDAR *c)
741 {
742 	UINT num;
743 	UINT i;
744 	CONNECTION **connections;
745 	// Validate arguments
746 	if (c == NULL)
747 	{
748 		return;
749 	}
750 
751 	LockList(c->ConnectionList);
752 	{
753 		connections = ToArray(c->ConnectionList);
754 		num = LIST_NUM(c->ConnectionList);
755 		DeleteAll(c->ConnectionList);
756 	}
757 	UnlockList(c->ConnectionList);
758 
759 	for (i = 0;i < num;i++)
760 	{
761 		StopConnection(connections[i], false);
762 		ReleaseConnection(connections[i]);
763 	}
764 	Free(connections);
765 }
766 
767 // Delete a hub in Cedar
DelHub(CEDAR * c,HUB * h)768 void DelHub(CEDAR *c, HUB *h)
769 {
770 	DelHubEx(c, h, false);
771 }
DelHubEx(CEDAR * c,HUB * h,bool no_lock)772 void DelHubEx(CEDAR *c, HUB *h, bool no_lock)
773 {
774 	// Validate arguments
775 	if (c == NULL || h == NULL)
776 	{
777 		return;
778 	}
779 
780 	if (no_lock == false)
781 	{
782 		LockHubList(c);
783 	}
784 
785 	if (Delete(c->HubList, h))
786 	{
787 		ReleaseHub(h);
788 	}
789 
790 	if (no_lock == false)
791 	{
792 		UnlockHubList(c);
793 	}
794 }
795 
796 // Add a new hub to Cedar
AddHub(CEDAR * c,HUB * h)797 void AddHub(CEDAR *c, HUB *h)
798 {
799 	// Validate arguments
800 	if (c == NULL || h == NULL)
801 	{
802 		return;
803 	}
804 
805 	LockHubList(c);
806 	{
807 #if	0
808 		// We shall not check here the number of hub
809 		if (LIST_NUM(c->HubList) >= MAX_HUBS)
810 		{
811 			// over limit
812 			UnlockHubList(c);
813 			return;
814 		}
815 #endif
816 
817 		// Confirm there is no hub which have same name
818 		if (IsHub(c, h->Name))
819 		{
820 			// exist
821 			UnlockHubList(c);
822 			return;
823 		}
824 
825 		// Register the hub
826 		Insert(c->HubList, h);
827 		AddRef(h->ref);
828 	}
829 	UnlockHubList(c);
830 }
831 
832 // Stop all hubs in Cedar
StopAllHub(CEDAR * c)833 void StopAllHub(CEDAR *c)
834 {
835 	HUB **hubs;
836 	UINT i, num;
837 	// Validate arguments
838 	if (c == NULL)
839 	{
840 		return;
841 	}
842 
843 	LockHubList(c);
844 	{
845 		hubs = ToArray(c->HubList);
846 		num = LIST_NUM(c->HubList);
847 		DeleteAll(c->HubList);
848 	}
849 	UnlockHubList(c);
850 
851 	for (i = 0;i < num;i++)
852 	{
853 		StopHub(hubs[i]);
854 		ReleaseHub(hubs[i]);
855 	}
856 
857 	Free(hubs);
858 }
859 
860 // Get reverse listener socket in Cedar
GetReverseListeningSock(CEDAR * c)861 SOCK *GetReverseListeningSock(CEDAR *c)
862 {
863 	SOCK *s = NULL;
864 	// Validate arguments
865 	if (c == NULL)
866 	{
867 		return NULL;
868 	}
869 
870 	LockList(c->ListenerList);
871 	{
872 		UINT i;
873 		for (i = 0;i < LIST_NUM(c->ListenerList);i++)
874 		{
875 			LISTENER *r = LIST_DATA(c->ListenerList, i);
876 
877 			if (r->Protocol == LISTENER_REVERSE)
878 			{
879 				Lock(r->lock);
880 				{
881 					s = r->Sock;
882 
883 					AddRef(s->ref);
884 				}
885 				Unlock(r->lock);
886 				break;
887 			}
888 		}
889 	}
890 	UnlockList(c->ListenerList);
891 
892 	return s;
893 }
894 
895 // Get in-process listener socket in Cedar
GetInProcListeningSock(CEDAR * c)896 SOCK *GetInProcListeningSock(CEDAR *c)
897 {
898 	SOCK *s = NULL;
899 	// Validate arguments
900 	if (c == NULL)
901 	{
902 		return NULL;
903 	}
904 
905 	LockList(c->ListenerList);
906 	{
907 		UINT i;
908 		for (i = 0;i < LIST_NUM(c->ListenerList);i++)
909 		{
910 			LISTENER *r = LIST_DATA(c->ListenerList, i);
911 
912 			if (r->Protocol == LISTENER_INPROC)
913 			{
914 				Lock(r->lock);
915 				{
916 					s = r->Sock;
917 
918 					if (s != NULL)
919 					{
920 						AddRef(s->ref);
921 					}
922 				}
923 				Unlock(r->lock);
924 				break;
925 			}
926 		}
927 	}
928 	UnlockList(c->ListenerList);
929 
930 	return s;
931 }
932 
933 // Add a new listener to Cedar
AddListener(CEDAR * c,LISTENER * r)934 void AddListener(CEDAR *c, LISTENER *r)
935 {
936 	// Validate arguments
937 	if (c == NULL || r == NULL)
938 	{
939 		return;
940 	}
941 
942 	LockList(c->ListenerList);
943 	{
944 		Add(c->ListenerList, r);
945 		AddRef(r->ref);
946 	}
947 	UnlockList(c->ListenerList);
948 }
949 
950 // Stop all listener in Cedar
StopAllListener(CEDAR * c)951 void StopAllListener(CEDAR *c)
952 {
953 	LISTENER **array;
954 	UINT i, num;
955 	// Validate arguments
956 	if (c == NULL)
957 	{
958 		return;
959 	}
960 
961 	LockList(c->ListenerList);
962 	{
963 		array = ToArray(c->ListenerList);
964 		num = LIST_NUM(c->ListenerList);
965 		DeleteAll(c->ListenerList);
966 	}
967 	UnlockList(c->ListenerList);
968 
969 	for (i = 0;i < num;i++)
970 	{
971 		StopListener(array[i]);
972 		ReleaseListener(array[i]);
973 	}
974 	Free(array);
975 }
976 
977 // Budget management functions
CedarAddQueueBudget(CEDAR * c,int diff)978 void CedarAddQueueBudget(CEDAR *c, int diff)
979 {
980 	// Validate arguments
981 	if (c == NULL || diff == 0)
982 	{
983 		return;
984 	}
985 
986 	Lock(c->QueueBudgetLock);
987 	{
988 		int v = (int)c->QueueBudget;
989 		v += diff;
990 		c->QueueBudget = (UINT)v;
991 	}
992 	Unlock(c->QueueBudgetLock);
993 }
CedarAddFifoBudget(CEDAR * c,int diff)994 void CedarAddFifoBudget(CEDAR *c, int diff)
995 {
996 	// Validate arguments
997 	if (c == NULL || diff == 0)
998 	{
999 		return;
1000 	}
1001 
1002 	Lock(c->FifoBudgetLock);
1003 	{
1004 		int v = (int)c->FifoBudget;
1005 		v += diff;
1006 		c->FifoBudget = (UINT)v;
1007 	}
1008 	Unlock(c->FifoBudgetLock);
1009 }
CedarGetQueueBudgetConsuming(CEDAR * c)1010 UINT CedarGetQueueBudgetConsuming(CEDAR *c)
1011 {
1012 	// Validate arguments
1013 	if (c == NULL)
1014 	{
1015 		return 0;
1016 	}
1017 
1018 	return c->QueueBudget;
1019 }
CedarGetFifoBudgetConsuming(CEDAR * c)1020 UINT CedarGetFifoBudgetConsuming(CEDAR *c)
1021 {
1022 	// Validate arguments
1023 	if (c == NULL)
1024 	{
1025 		return 0;
1026 	}
1027 
1028 	return c->FifoBudget;
1029 }
CedarGetQueueBudgetBalance(CEDAR * c)1030 UINT CedarGetQueueBudgetBalance(CEDAR *c)
1031 {
1032 	UINT current = CedarGetQueueBudgetConsuming(c);
1033 	UINT budget = QUEUE_BUDGET;
1034 
1035 	if (current <= budget)
1036 	{
1037 		return budget - current;
1038 	}
1039 	else
1040 	{
1041 		return 0;
1042 	}
1043 }
CedarGetFifoBudgetBalance(CEDAR * c)1044 UINT CedarGetFifoBudgetBalance(CEDAR *c)
1045 {
1046 	UINT current = CedarGetFifoBudgetConsuming(c);
1047 	UINT budget = FIFO_BUDGET;
1048 
1049 	if (current <= budget)
1050 	{
1051 		return budget - current;
1052 	}
1053 	else
1054 	{
1055 		return 0;
1056 	}
1057 }
1058 
1059 // Add the current TCP queue size
CedarAddCurrentTcpQueueSize(CEDAR * c,int diff)1060 void CedarAddCurrentTcpQueueSize(CEDAR *c, int diff)
1061 {
1062 	// Validate arguments
1063 	if (c == NULL || diff == 0)
1064 	{
1065 		return;
1066 	}
1067 
1068 	Lock(c->CurrentTcpQueueSizeLock);
1069 	{
1070 		int v = (int)c->CurrentTcpQueueSize;
1071 		v += diff;
1072 		c->CurrentTcpQueueSize = (UINT)v;
1073 	}
1074 	Unlock(c->CurrentTcpQueueSizeLock);
1075 }
1076 
1077 // Get the current TCP queue size
CedarGetCurrentTcpQueueSize(CEDAR * c)1078 UINT CedarGetCurrentTcpQueueSize(CEDAR *c)
1079 {
1080 	// Validate arguments
1081 	if (c == NULL)
1082 	{
1083 		return 0;
1084 	}
1085 
1086 	return c->CurrentTcpQueueSize;
1087 }
1088 
1089 // Stop Cedar
StopCedar(CEDAR * c)1090 void StopCedar(CEDAR *c)
1091 {
1092 	// Validate arguments
1093 	if (c == NULL)
1094 	{
1095 		return;
1096 	}
1097 
1098 	// Stop flag
1099 	c->Halt = true;
1100 
1101 	// Stop all listener
1102 	StopAllListener(c);
1103 	// Stop all connections
1104 	StopAllConnection(c);
1105 	// Stop all hubs
1106 	StopAllHub(c);
1107 	// Free all virtual L3 switch
1108 	L3FreeAllSw(c);
1109 }
1110 
1111 // Clean up Cedar
CleanupCedar(CEDAR * c)1112 void CleanupCedar(CEDAR *c)
1113 {
1114 	UINT i;
1115 	// Validate arguments
1116 	if (c == NULL)
1117 	{
1118 		return;
1119 	}
1120 
1121 	WuFreeWebUI(c->WebUI);
1122 	FreeCedarLayer3(c);
1123 
1124 	for (i = 0; i < LIST_NUM(c->WgkList); ++i)
1125 	{
1126 		WGK *wgk = LIST_DATA(c->WgkList, i);
1127 		Free(wgk);
1128 	}
1129 	ReleaseList(c->WgkList);
1130 
1131 	for (i = 0;i < LIST_NUM(c->CaList);i++)
1132 	{
1133 		X *x = LIST_DATA(c->CaList, i);
1134 		FreeX(x);
1135 	}
1136 	ReleaseList(c->CaList);
1137 
1138 	ReleaseList(c->ListenerList);
1139 	ReleaseList(c->HubList);
1140 	ReleaseList(c->ConnectionList);
1141 	//CleanupUDPEntry(c);
1142 	ReleaseList(c->UDPEntryList);
1143 	DeleteLock(c->lock);
1144 	DeleteCounter(c->ConnectionIncrement);
1145 	DeleteCounter(c->CurrentSessions);
1146 
1147 	if (c->DebugLog != NULL)
1148 	{
1149 		FreeLog(c->DebugLog);
1150 	}
1151 
1152 	if (c->ServerX)
1153 	{
1154 		FreeX(c->ServerX);
1155 	}
1156 	if (c->ServerK)
1157 	{
1158 		FreeK(c->ServerK);
1159 	}
1160 
1161 	if (c->CipherList)
1162 	{
1163 		Free(c->CipherList);
1164 	}
1165 
1166 	for (i = 0;i < LIST_NUM(c->TrafficDiffList);i++)
1167 	{
1168 		TRAFFIC_DIFF *d = LIST_DATA(c->TrafficDiffList, i);
1169 		Free(d->Name);
1170 		Free(d->HubName);
1171 		Free(d);
1172 	}
1173 
1174 	ReleaseList(c->TrafficDiffList);
1175 
1176 	Free(c->ServerStr);
1177 	Free(c->MachineName);
1178 
1179 	Free(c->HttpUserAgent);
1180 	Free(c->HttpAccept);
1181 	Free(c->HttpAcceptLanguage);
1182 	Free(c->HttpAcceptEncoding);
1183 
1184 	FreeTraffic(c->Traffic);
1185 
1186 	DeleteLock(c->TrafficLock);
1187 
1188 	FreeNetSvcList(c);
1189 
1190 	Free(c->VerString);
1191 	Free(c->BuildInfo);
1192 
1193 	FreeLocalBridgeList(c);
1194 
1195 	DeleteCounter(c->AssignedBridgeLicense);
1196 	DeleteCounter(c->AssignedClientLicense);
1197 
1198 	FreeNoSslList(c);
1199 
1200 	DeleteLock(c->CedarSuperLock);
1201 
1202 	DeleteCounter(c->AcceptingSockets);
1203 
1204 	ReleaseIntList(c->UdpPortList);
1205 
1206 	DeleteLock(c->OpenVPNPublicPortsLock);
1207 
1208 	DeleteLock(c->CurrentRegionLock);
1209 
1210 	DeleteLock(c->CurrentTcpQueueSizeLock);
1211 	DeleteLock(c->QueueBudgetLock);
1212 	DeleteLock(c->FifoBudgetLock);
1213 
1214 	DeleteCounter(c->CurrentActiveLinks);
1215 
1216 	Free(c);
1217 }
1218 
1219 // Release reference of the Cedar
ReleaseCedar(CEDAR * c)1220 void ReleaseCedar(CEDAR *c)
1221 {
1222 	// Validate arguments
1223 	if (c == NULL)
1224 	{
1225 		return;
1226 	}
1227 
1228 	if (Release(c->ref) == 0)
1229 	{
1230 		CleanupCedar(c);
1231 	}
1232 }
1233 
1234 // Set cipher list entry
SetCedarCipherList(CEDAR * cedar,char * name)1235 void SetCedarCipherList(CEDAR *cedar, char *name)
1236 {
1237 	// Validate arguments
1238 	if (cedar == NULL)
1239 	{
1240 		return;
1241 	}
1242 
1243 	if (cedar->CipherList != NULL)
1244 	{
1245 		Free(cedar->CipherList);
1246 	}
1247 	if (name != NULL)
1248 	{
1249 		cedar->CipherList = CopyStr(name);
1250 	}
1251 	else
1252 	{
1253 		cedar->CipherList = NULL;
1254 	}
1255 }
1256 
1257 // Compare net service list entries
CompareNetSvc(void * p1,void * p2)1258 int CompareNetSvc(void *p1, void *p2)
1259 {
1260 	NETSVC *n1, *n2;
1261 	if (p1 == NULL || p2 == NULL)
1262 	{
1263 		return 0;
1264 	}
1265 	n1 = *(NETSVC **)p1;
1266 	n2 = *(NETSVC **)p2;
1267 	if (n1 == NULL || n2 == NULL)
1268 	{
1269 		return 0;
1270 	}
1271 	if (n1->Port > n2->Port)
1272 	{
1273 		return 1;
1274 	}
1275 	else if (n1->Port < n2->Port)
1276 	{
1277 		return -1;
1278 	}
1279 	else if (n1->Udp > n2->Udp)
1280 	{
1281 		return 1;
1282 	}
1283 	else if (n1->Udp < n2->Udp)
1284 	{
1285 		return -1;
1286 	}
1287 	return 0;
1288 }
1289 
1290 // Initialize net service list
InitNetSvcList(CEDAR * cedar)1291 void InitNetSvcList(CEDAR *cedar)
1292 {
1293 	char filename[MAX_PATH] = "/etc/services";
1294 	BUF *b;
1295 	// Validate arguments
1296 	if (cedar == NULL)
1297 	{
1298 		return;
1299 	}
1300 
1301 #ifdef	OS_WIN32
1302 	Format(filename, sizeof(filename), "%s\\drivers\\etc\\services", MsGetSystem32Dir());
1303 #endif
1304 
1305 	cedar->NetSvcList = NewList(CompareNetSvc);
1306 
1307 	b = ReadDump(filename);
1308 	if (b == NULL)
1309 	{
1310 		return;
1311 	}
1312 
1313 	while (true)
1314 	{
1315 		char *s = CfgReadNextLine(b);
1316 		if (s == NULL)
1317 		{
1318 			break;
1319 		}
1320 
1321 		Trim(s);
1322 		if (s[0] != '#')
1323 		{
1324 			TOKEN_LIST *t = ParseToken(s, " \t/");
1325 			if (t->NumTokens >= 3)
1326 			{
1327 				NETSVC *n = ZeroMalloc(sizeof(NETSVC));
1328 				n->Name = CopyStr(t->Token[0]);
1329 				n->Udp = (StrCmpi(t->Token[2], "udp") == 0 ? true : false);
1330 				n->Port = ToInt(t->Token[1]);
1331 				Add(cedar->NetSvcList, n);
1332 			}
1333 			FreeToken(t);
1334 		}
1335 		Free(s);
1336 	}
1337 
1338 	FreeBuf(b);
1339 }
1340 
1341 // Get net service name
GetSvcName(CEDAR * cedar,bool udp,UINT port)1342 char *GetSvcName(CEDAR *cedar, bool udp, UINT port)
1343 {
1344 	char *ret = NULL;
1345 	NETSVC t;
1346 	// Validate arguments
1347 	if (cedar == NULL)
1348 	{
1349 		return NULL;
1350 	}
1351 
1352 	t.Udp = (udp == 0 ? false : true);
1353 	t.Port = port;
1354 
1355 	LockList(cedar->NetSvcList);
1356 	{
1357 		NETSVC *n = Search(cedar->NetSvcList, &t);
1358 		if (n != NULL)
1359 		{
1360 			ret = n->Name;
1361 		}
1362 	}
1363 	UnlockList(cedar->NetSvcList);
1364 
1365 	return ret;
1366 }
1367 
1368 // Free net service list
FreeNetSvcList(CEDAR * cedar)1369 void FreeNetSvcList(CEDAR *cedar)
1370 {
1371 	UINT i;
1372 	// Validate arguments
1373 	if (cedar == NULL)
1374 	{
1375 		return;
1376 	}
1377 
1378 	for (i = 0;i < LIST_NUM(cedar->NetSvcList);i++)
1379 	{
1380 		NETSVC *n = LIST_DATA(cedar->NetSvcList, i);
1381 		Free(n->Name);
1382 		Free(n);
1383 	}
1384 	ReleaseList(cedar->NetSvcList);
1385 }
1386 
1387 // Change certificate of Cedar
SetCedarCert(CEDAR * c,X * server_x,K * server_k)1388 void SetCedarCert(CEDAR *c, X *server_x, K *server_k)
1389 {
1390 	// Validate arguments
1391 	if (server_x == NULL || server_k == NULL)
1392 	{
1393 		return;
1394 	}
1395 
1396 	Lock(c->lock);
1397 	{
1398 		if (c->ServerX != NULL)
1399 		{
1400 			FreeX(c->ServerX);
1401 		}
1402 
1403 		if (c->ServerK != NULL)
1404 		{
1405 			FreeK(c->ServerK);
1406 		}
1407 
1408 		c->ServerX = CloneX(server_x);
1409 		c->ServerK = CloneK(server_k);
1410 	}
1411 	Unlock(c->lock);
1412 }
1413 
1414 // Set the Cedar into VPN Bridge mode
SetCedarVpnBridge(CEDAR * c)1415 void SetCedarVpnBridge(CEDAR *c)
1416 {
1417 	// Validate arguments
1418 	if (c == NULL)
1419 	{
1420 		return;
1421 	}
1422 
1423 	c->Bridge = true;
1424 
1425 	Free(c->ServerStr);
1426 	c->ServerStr = CopyStr(CEDAR_BRIDGE_STR);
1427 }
1428 
CedarForceLink()1429 void CedarForceLink()
1430 {
1431 }
1432 
1433 // Get version of the Cedar
GetCedarVersion(char * tmp,UINT size)1434 void GetCedarVersion(char *tmp, UINT size)
1435 {
1436 	// Validate arguments
1437 	if (tmp == NULL)
1438 	{
1439 		return;
1440 	}
1441 
1442 	Format(tmp, size, "%u.%02u.%u", CEDAR_VERSION_MAJOR, CEDAR_VERSION_MINOR, CEDAR_VERSION_BUILD);
1443 }
1444 
GetCedarVersionNumber()1445 UINT GetCedarVersionNumber()
1446 {
1447 	return CEDAR_VERSION_MAJOR * 100 + CEDAR_VERSION_MINOR;
1448 }
1449 
1450 // Create Cedar object
NewCedar(X * server_x,K * server_k)1451 CEDAR *NewCedar(X *server_x, K *server_k)
1452 {
1453 	CEDAR *c;
1454 	char tmp[MAX_SIZE];
1455 	char tmp2[MAX_SIZE];
1456 	char *beta_str;
1457 
1458 	CedarForceLink();
1459 
1460 	c = ZeroMalloc(sizeof(CEDAR));
1461 
1462 	c->CurrentActiveLinks = NewCounter();
1463 
1464 	c->AcceptingSockets = NewCounter();
1465 
1466 	c->CedarSuperLock = NewLock();
1467 
1468 	c->CurrentRegionLock = NewLock();
1469 
1470 #ifdef	BETA_NUMBER
1471 	c->Beta = BETA_NUMBER;
1472 #endif	// BETA_NUMBER
1473 
1474 	InitNoSslList(c);
1475 
1476 	c->AssignedBridgeLicense = NewCounter();
1477 	c->AssignedClientLicense = NewCounter();
1478 
1479 	c->CurrentTcpQueueSizeLock = NewLock();
1480 	c->QueueBudgetLock = NewLock();
1481 	c->FifoBudgetLock = NewLock();
1482 
1483 	Rand(c->UniqueId, sizeof(c->UniqueId));
1484 
1485 	c->CreatedTick = Tick64();
1486 
1487 	c->lock = NewLock();
1488 	c->ref = NewRef();
1489 
1490 	c->OpenVPNPublicPortsLock = NewLock();
1491 	c->CurrentTcpConnections = GetNumTcpConnectionsCounter();
1492 
1493 	c->ListenerList = NewList(CompareListener);
1494 	c->UDPEntryList = NewList(CompareUDPEntry);
1495 	c->HubList = NewList(CompareHub);
1496 	c->ConnectionList = NewList(CompareConnection);
1497 
1498 	c->ConnectionIncrement = NewCounter();
1499 	c->CurrentSessions = NewCounter();
1500 
1501 	if (server_k && server_x)
1502 	{
1503 		c->ServerK = CloneK(server_k);
1504 		c->ServerX = CloneX(server_x);
1505 	}
1506 
1507 	c->Version = GetCedarVersionNumber();
1508 	c->Build = CEDAR_VERSION_BUILD;
1509 	c->ServerStr = CopyStr(CEDAR_SERVER_STR);
1510 
1511 	GetMachineName(tmp, sizeof(tmp));
1512 	c->MachineName = CopyStr(tmp);
1513 
1514 	c->HttpUserAgent = CopyStr(DEFAULT_USER_AGENT);
1515 	c->HttpAccept = CopyStr(DEFAULT_ACCEPT);
1516 	c->HttpAcceptLanguage = CopyStr("ja");
1517 	c->HttpAcceptEncoding = CopyStr(DEFAULT_ENCODING);
1518 
1519 	c->Traffic = NewTraffic();
1520 	c->TrafficLock = NewLock();
1521 	c->CaList = NewList(CompareCert);
1522 	c->WgkList = NewList(CompareWgk);
1523 
1524 	c->TrafficDiffList = NewList(NULL);
1525 
1526 	SetCedarCipherList(c, SERVER_DEFAULT_CIPHER_NAME);
1527 
1528 	c->ClientId = _II("CLIENT_ID");
1529 
1530 	c->UdpPortList = NewIntList(false);
1531 
1532 	c->DhParamBits = DH_PARAM_BITS_DEFAULT;
1533 
1534 	InitNetSvcList(c);
1535 
1536 	InitLocalBridgeList(c);
1537 
1538 	InitCedarLayer3(c);
1539 
1540 	c->WebUI = WuNewWebUI(c);
1541 
1542 #ifdef	ALPHA_VERSION
1543 	beta_str = "Alpha";
1544 #else	// ALPHA_VERSION
1545 #ifndef	RELEASE_CANDIDATE
1546 	beta_str = "Beta";
1547 #else	// RELEASE_CANDIDATE
1548 	beta_str = "Release Candidate";
1549 #endif	// RELEASE_CANDIDATE
1550 #endif	// ALPHA_VERSION
1551 
1552 	ToStr(tmp2, c->Beta);
1553 
1554 	Format(tmp, sizeof(tmp), "Version %u.%02u Build %u %s %s (%s)",
1555 		CEDAR_VERSION_MAJOR, CEDAR_VERSION_MINOR, CEDAR_VERSION_BUILD,
1556 		c->Beta == 0 ? "" : beta_str,
1557 		c->Beta == 0 ? "" : tmp2,
1558 		_SS("LANGSTR"));
1559 	Trim(tmp);
1560 
1561 	if (true)
1562 	{
1563 		SYSTEMTIME st;
1564 		Zero(&st, sizeof(st));
1565 
1566 		st.wYear = BUILD_DATE_Y;
1567 		st.wMonth = BUILD_DATE_M;
1568 		st.wDay = BUILD_DATE_D;
1569 
1570 		c->BuiltDate = SystemToUINT64(&st);
1571 	}
1572 
1573 	c->VerString = CopyStr(tmp);
1574 
1575 	Format(tmp, sizeof(tmp), "Compiled %04u/%02u/%02u %02u:%02u:%02u by %s at %s",
1576 		BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D, BUILD_DATE_HO, BUILD_DATE_MI, BUILD_DATE_SE, BUILDER_NAME, BUILD_PLACE);
1577 
1578 	c->BuildInfo = CopyStr(tmp);
1579 
1580 	return c;
1581 }
1582 
1583 // Cumulate traffic size
AddTraffic(TRAFFIC * dst,TRAFFIC * diff)1584 void AddTraffic(TRAFFIC *dst, TRAFFIC *diff)
1585 {
1586 	// Validate arguments
1587 	if (dst == NULL || diff == NULL)
1588 	{
1589 		return;
1590 	}
1591 
1592 	dst->Recv.BroadcastBytes += diff->Recv.BroadcastBytes;
1593 	dst->Recv.BroadcastCount += diff->Recv.BroadcastCount;
1594 	dst->Recv.UnicastBytes += diff->Recv.UnicastBytes;
1595 	dst->Recv.UnicastCount += diff->Recv.UnicastCount;
1596 
1597 	dst->Send.BroadcastBytes += diff->Send.BroadcastBytes;
1598 	dst->Send.BroadcastCount += diff->Send.BroadcastCount;
1599 	dst->Send.UnicastBytes += diff->Send.UnicastBytes;
1600 	dst->Send.UnicastCount += diff->Send.UnicastCount;
1601 }
1602 
1603 // Create new traffic size object
NewTraffic()1604 TRAFFIC *NewTraffic()
1605 {
1606 	TRAFFIC *t;
1607 
1608 	t = ZeroMalloc(sizeof(TRAFFIC));
1609 	return t;
1610 }
1611 
1612 // Free traffic size object
FreeTraffic(TRAFFIC * t)1613 void FreeTraffic(TRAFFIC *t)
1614 {
1615 	// Validate arguments
1616 	if (t == NULL)
1617 	{
1618 		return;
1619 	}
1620 
1621 	Free(t);
1622 }
1623 
1624 // Initialize Cedar communication module
InitCedar()1625 void InitCedar()
1626 {
1627 	if ((init_cedar_counter++) > 0)
1628 	{
1629 		return;
1630 	}
1631 
1632 	if (sodium_init() == -1)
1633 	{
1634 		Debug("InitCedar(): sodium_init() failed!\n");
1635 		return;
1636 	}
1637 
1638 	// Initialize protocol module
1639 	InitProtocol();
1640 }
1641 
1642 // Free Cedar communication module
FreeCedar()1643 void FreeCedar()
1644 {
1645 	if ((--init_cedar_counter) > 0)
1646 	{
1647 		return;
1648 	}
1649 
1650 	// Free protocol module
1651 	FreeProtocol();
1652 }
1653 
1654