eap-radius: Increase Acct-Session-ID string buffer
[strongswan.git] / src / libcharon / plugins / eap_radius / eap_radius_accounting.c
1 /*
2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "eap_radius_accounting.h"
17 #include "eap_radius_plugin.h"
18
19 #include <time.h>
20
21 #include <radius_message.h>
22 #include <radius_client.h>
23 #include <daemon.h>
24 #include <collections/hashtable.h>
25 #include <threading/mutex.h>
26 #include <processing/jobs/callback_job.h>
27
28 typedef struct private_eap_radius_accounting_t private_eap_radius_accounting_t;
29
30 /**
31 * Private data of an eap_radius_accounting_t object.
32 */
33 struct private_eap_radius_accounting_t {
34
35 /**
36 * Public eap_radius_accounting_t interface.
37 */
38 eap_radius_accounting_t public;
39
40 /**
41 * Hashtable with sessions, ike_sa_id_t => entry_t
42 */
43 hashtable_t *sessions;
44
45 /**
46 * Mutex to lock sessions
47 */
48 mutex_t *mutex;
49
50 /**
51 * Session ID prefix
52 */
53 u_int32_t prefix;
54
55 /**
56 * Format string we use for Called/Calling-Station-Id for a host
57 */
58 char *station_id_fmt;
59
60 /**
61 * Disable accounting unless IKE_SA has at least one virtual IP
62 */
63 bool acct_req_vip;
64 };
65
66 /**
67 * Singleton instance of accounting
68 */
69 static private_eap_radius_accounting_t *singleton = NULL;
70
71 /**
72 * Acct-Terminate-Cause
73 */
74 typedef enum {
75 ACCT_CAUSE_USER_REQUEST = 1,
76 ACCT_CAUSE_LOST_CARRIER = 2,
77 ACCT_CAUSE_LOST_SERVICE = 3,
78 ACCT_CAUSE_IDLE_TIMEOUT = 4,
79 ACCT_CAUSE_SESSION_TIMEOUT = 5,
80 ACCT_CAUSE_ADMIN_RESET = 6,
81 ACCT_CAUSE_ADMIN_REBOOT = 7,
82 ACCT_CAUSE_PORT_ERROR = 8,
83 ACCT_CAUSE_NAS_ERROR = 9,
84 ACCT_CAUSE_NAS_REQUEST = 10,
85 ACCT_CAUSE_NAS_REBOOT = 11,
86 ACCT_CAUSE_PORT_UNNEEDED = 12,
87 ACCT_CAUSE_PORT_PREEMPTED = 13,
88 ACCT_CAUSE_PORT_SUSPENDED = 14,
89 ACCT_CAUSE_SERVICE_UNAVAILABLE = 15,
90 ACCT_CAUSE_CALLBACK = 16,
91 ACCT_CAUSE_USER_ERROR = 17,
92 ACCT_CAUSE_HOST_REQUEST = 18,
93 } radius_acct_terminate_cause_t;
94
95 /**
96 * Hashtable entry with usage stats
97 */
98 typedef struct {
99 /** IKE_SA identifier this entry is stored under */
100 ike_sa_id_t *id;
101 /** RADIUS accounting session ID */
102 char sid[24];
103 /** number of sent/received octets/packets */
104 struct {
105 u_int64_t sent;
106 u_int64_t received;
107 } bytes, packets;
108 /** session creation time */
109 time_t created;
110 /** terminate cause */
111 radius_acct_terminate_cause_t cause;
112 /* interim interval and timestamp of last update */
113 struct {
114 u_int32_t interval;
115 time_t last;
116 } interim;
117 /** did we send Accounting-Start */
118 bool start_sent;
119 } entry_t;
120
121 /**
122 * Destroy an entry_t
123 */
124 static void destroy_entry(entry_t *this)
125 {
126 this->id->destroy(this->id);
127 free(this);
128 }
129
130 /**
131 * Accounting message status types
132 */
133 typedef enum {
134 ACCT_STATUS_START = 1,
135 ACCT_STATUS_STOP = 2,
136 ACCT_STATUS_INTERIM_UPDATE = 3,
137 ACCT_STATUS_ACCOUNTING_ON = 7,
138 ACCT_STATUS_ACCOUNTING_OFF = 8,
139 } radius_acct_status_t;
140
141 /**
142 * Hashtable hash function
143 */
144 static u_int hash(ike_sa_id_t *key)
145 {
146 return key->get_responder_spi(key);
147 }
148
149 /**
150 * Hashtable equals function
151 */
152 static bool equals(ike_sa_id_t *a, ike_sa_id_t *b)
153 {
154 return a->equals(a, b);
155 }
156
157 /**
158 * Update usage counter when a CHILD_SA rekeys/goes down
159 */
160 static void update_usage(private_eap_radius_accounting_t *this,
161 ike_sa_t *ike_sa, child_sa_t *child_sa)
162 {
163 u_int64_t bytes_in, bytes_out, packets_in, packets_out;
164 entry_t *entry;
165
166 child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, &packets_out);
167 child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in, &packets_in);
168
169 this->mutex->lock(this->mutex);
170 entry = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa));
171 if (entry)
172 {
173 entry->bytes.sent += bytes_out;
174 entry->bytes.received += bytes_in;
175 entry->packets.sent += packets_out;
176 entry->packets.received += packets_in;
177 }
178 this->mutex->unlock(this->mutex);
179 }
180
181 /**
182 * Send a RADIUS message, wait for response
183 */
184 static bool send_message(private_eap_radius_accounting_t *this,
185 radius_message_t *request)
186 {
187 radius_message_t *response;
188 radius_client_t *client;
189 bool ack = FALSE;
190
191 client = eap_radius_create_client();
192 if (client)
193 {
194 response = client->request(client, request);
195 if (response)
196 {
197 ack = response->get_code(response) == RMC_ACCOUNTING_RESPONSE;
198 response->destroy(response);
199 }
200 client->destroy(client);
201 }
202 return ack;
203 }
204
205 /**
206 * Add common IKE_SA parameters to RADIUS account message
207 */
208 static void add_ike_sa_parameters(private_eap_radius_accounting_t *this,
209 radius_message_t *message, ike_sa_t *ike_sa)
210 {
211 enumerator_t *enumerator;
212 host_t *vip, *host;
213 char buf[MAX_RADIUS_ATTRIBUTE_SIZE + 1];
214 chunk_t data;
215 u_int32_t value;
216
217 /* virtual NAS-Port-Type */
218 value = htonl(5);
219 message->add(message, RAT_NAS_PORT_TYPE, chunk_from_thing(value));
220 /* framed ServiceType */
221 value = htonl(2);
222 message->add(message, RAT_SERVICE_TYPE, chunk_from_thing(value));
223
224 value = htonl(ike_sa->get_unique_id(ike_sa));
225 message->add(message, RAT_NAS_PORT, chunk_from_thing(value));
226 message->add(message, RAT_NAS_PORT_ID,
227 chunk_from_str(ike_sa->get_name(ike_sa)));
228
229 host = ike_sa->get_my_host(ike_sa);
230 data = host->get_address(host);
231 switch (host->get_family(host))
232 {
233 case AF_INET:
234 message->add(message, RAT_NAS_IP_ADDRESS, data);
235 break;
236 case AF_INET6:
237 message->add(message, RAT_NAS_IPV6_ADDRESS, data);
238 default:
239 break;
240 }
241 snprintf(buf, sizeof(buf), this->station_id_fmt, host);
242 message->add(message, RAT_CALLED_STATION_ID, chunk_from_str(buf));
243 host = ike_sa->get_other_host(ike_sa);
244 snprintf(buf, sizeof(buf), this->station_id_fmt, host);
245 message->add(message, RAT_CALLING_STATION_ID, chunk_from_str(buf));
246
247 snprintf(buf, sizeof(buf), "%Y", ike_sa->get_other_eap_id(ike_sa));
248 message->add(message, RAT_USER_NAME, chunk_from_str(buf));
249
250 enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
251 while (enumerator->enumerate(enumerator, &vip))
252 {
253 switch (vip->get_family(vip))
254 {
255 case AF_INET:
256 message->add(message, RAT_FRAMED_IP_ADDRESS,
257 vip->get_address(vip));
258 break;
259 case AF_INET6:
260 /* we currently assign /128 prefixes, only (reserved, length) */
261 data = chunk_from_chars(0, 128);
262 data = chunk_cata("cc", data, vip->get_address(vip));
263 message->add(message, RAT_FRAMED_IPV6_PREFIX, data);
264 break;
265 default:
266 break;
267 }
268 }
269 enumerator->destroy(enumerator);
270 }
271
272 /**
273 * Get an existing or create a new entry from the locked session table
274 */
275 static entry_t* get_or_create_entry(private_eap_radius_accounting_t *this,
276 ike_sa_t *ike_sa)
277 {
278 ike_sa_id_t *id;
279 entry_t *entry;
280 time_t now;
281
282 entry = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa));
283 if (!entry)
284 {
285 now = time_monotonic(NULL);
286 id = ike_sa->get_id(ike_sa);
287
288 INIT(entry,
289 .id = id->clone(id),
290 .created = now,
291 .interim = {
292 .last = now,
293 },
294 /* default terminate cause, if none other catched */
295 .cause = ACCT_CAUSE_USER_REQUEST,
296 );
297 snprintf(entry->sid, sizeof(entry->sid), "%u-%u",
298 this->prefix, ike_sa->get_unique_id(ike_sa));
299 this->sessions->put(this->sessions, entry->id, entry);
300 }
301 return entry;
302 }
303
304 /* forward declaration */
305 static void schedule_interim(private_eap_radius_accounting_t *this,
306 entry_t *entry);
307
308 /**
309 * Data passed to send_interim() using callback job
310 */
311 typedef struct {
312 /** reference to radius accounting */
313 private_eap_radius_accounting_t *this;
314 /** IKE_SA identifier to send interim update to */
315 ike_sa_id_t *id;
316 } interim_data_t;
317
318 /**
319 * Clean up interim data
320 */
321 void destroy_interim_data(interim_data_t *this)
322 {
323 this->id->destroy(this->id);
324 free(this);
325 }
326
327 /**
328 * Send an interim update for entry of given IKE_SA identifier
329 */
330 static job_requeue_t send_interim(interim_data_t *data)
331 {
332 private_eap_radius_accounting_t *this = data->this;
333 u_int64_t bytes_in = 0, bytes_out = 0, packets_in = 0, packets_out = 0;
334 u_int64_t bytes, packets;
335 radius_message_t *message = NULL;
336 enumerator_t *enumerator;
337 child_sa_t *child_sa;
338 ike_sa_t *ike_sa;
339 entry_t *entry;
340 u_int32_t value;
341
342 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, data->id);
343 if (!ike_sa)
344 {
345 return JOB_REQUEUE_NONE;
346 }
347 enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
348 while (enumerator->enumerate(enumerator, &child_sa))
349 {
350 child_sa->get_usestats(child_sa, FALSE, NULL, &bytes, &packets);
351 bytes_out += bytes;
352 packets_out += packets;
353 child_sa->get_usestats(child_sa, TRUE, NULL, &bytes, &packets);
354 bytes_in += bytes;
355 packets_in += packets;
356 }
357 enumerator->destroy(enumerator);
358 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
359
360 /* avoid any races by returning IKE_SA before acquiring lock */
361
362 this->mutex->lock(this->mutex);
363 entry = this->sessions->get(this->sessions, data->id);
364 if (entry)
365 {
366 entry->interim.last = time_monotonic(NULL);
367
368 bytes_in += entry->bytes.received;
369 bytes_out += entry->bytes.sent;
370 packets_in += entry->packets.received;
371 packets_out += entry->packets.sent;
372
373 message = radius_message_create(RMC_ACCOUNTING_REQUEST);
374 value = htonl(ACCT_STATUS_INTERIM_UPDATE);
375 message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
376 message->add(message, RAT_ACCT_SESSION_ID,
377 chunk_create(entry->sid, strlen(entry->sid)));
378 add_ike_sa_parameters(this, message, ike_sa);
379
380 value = htonl(bytes_out);
381 message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value));
382 value = htonl(bytes_out >> 32);
383 if (value)
384 {
385 message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS,
386 chunk_from_thing(value));
387 }
388 value = htonl(packets_out);
389 message->add(message, RAT_ACCT_OUTPUT_PACKETS, chunk_from_thing(value));
390
391 value = htonl(bytes_in);
392 message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value));
393 value = htonl(bytes_in >> 32);
394 if (value)
395 {
396 message->add(message, RAT_ACCT_INPUT_GIGAWORDS,
397 chunk_from_thing(value));
398 }
399 value = htonl(packets_in);
400 message->add(message, RAT_ACCT_INPUT_PACKETS, chunk_from_thing(value));
401
402 value = htonl(entry->interim.last - entry->created);
403 message->add(message, RAT_ACCT_SESSION_TIME, chunk_from_thing(value));
404
405 schedule_interim(this, entry);
406 }
407 this->mutex->unlock(this->mutex);
408
409 if (message)
410 {
411 if (!send_message(this, message))
412 {
413 if (lib->settings->get_bool(lib->settings,
414 "%s.plugins.eap-radius.accounting_close_on_timeout",
415 TRUE, lib->ns))
416 {
417 eap_radius_handle_timeout(data->id);
418 }
419 }
420 message->destroy(message);
421 }
422 return JOB_REQUEUE_NONE;
423 }
424
425 /**
426 * Schedule interim update for given entry
427 */
428 static void schedule_interim(private_eap_radius_accounting_t *this,
429 entry_t *entry)
430 {
431 if (entry->interim.interval)
432 {
433 interim_data_t *data;
434 timeval_t tv = {
435 .tv_sec = entry->interim.last + entry->interim.interval,
436 };
437
438 INIT(data,
439 .this = this,
440 .id = entry->id->clone(entry->id),
441 );
442 lib->scheduler->schedule_job_tv(lib->scheduler,
443 (job_t*)callback_job_create_with_prio(
444 (callback_job_cb_t)send_interim,
445 data, (void*)destroy_interim_data,
446 (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL), tv);
447 }
448 }
449
450 /**
451 * Check if an IKE_SA has assigned a virtual IP (to peer)
452 */
453 static bool has_vip(ike_sa_t *ike_sa)
454 {
455 enumerator_t *enumerator;
456 host_t *host;
457 bool found;
458
459 enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
460 found = enumerator->enumerate(enumerator, &host);
461 enumerator->destroy(enumerator);
462
463 return found;
464 }
465
466 /**
467 * Send an accounting start message
468 */
469 static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
470 {
471 radius_message_t *message;
472 entry_t *entry;
473 u_int32_t value;
474
475 if (this->acct_req_vip && !has_vip(ike_sa))
476 {
477 return;
478 }
479
480 this->mutex->lock(this->mutex);
481
482 entry = get_or_create_entry(this, ike_sa);
483 entry->start_sent = TRUE;
484
485 message = radius_message_create(RMC_ACCOUNTING_REQUEST);
486 value = htonl(ACCT_STATUS_START);
487 message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
488 message->add(message, RAT_ACCT_SESSION_ID,
489 chunk_create(entry->sid, strlen(entry->sid)));
490
491 if (!entry->interim.interval)
492 {
493 entry->interim.interval = lib->settings->get_time(lib->settings,
494 "%s.plugins.eap-radius.accounting_interval", 0, lib->ns);
495 if (entry->interim.interval)
496 {
497 DBG1(DBG_CFG, "scheduling RADIUS Interim-Updates every %us",
498 entry->interim.interval);
499 }
500 }
501 schedule_interim(this, entry);
502 this->mutex->unlock(this->mutex);
503
504 add_ike_sa_parameters(this, message, ike_sa);
505 if (!send_message(this, message))
506 {
507 eap_radius_handle_timeout(ike_sa->get_id(ike_sa));
508 }
509 message->destroy(message);
510 }
511
512 /**
513 * Send an account stop message
514 */
515 static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
516 {
517 radius_message_t *message;
518 entry_t *entry;
519 u_int32_t value;
520
521 this->mutex->lock(this->mutex);
522 entry = this->sessions->remove(this->sessions, ike_sa->get_id(ike_sa));
523 this->mutex->unlock(this->mutex);
524 if (entry)
525 {
526 if (!entry->start_sent)
527 { /* we tried to authenticate this peer, but never sent a start */
528 destroy_entry(entry);
529 return;
530 }
531 message = radius_message_create(RMC_ACCOUNTING_REQUEST);
532 value = htonl(ACCT_STATUS_STOP);
533 message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
534 message->add(message, RAT_ACCT_SESSION_ID,
535 chunk_create(entry->sid, strlen(entry->sid)));
536 add_ike_sa_parameters(this, message, ike_sa);
537
538 value = htonl(entry->bytes.sent);
539 message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value));
540 value = htonl(entry->bytes.sent >> 32);
541 if (value)
542 {
543 message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS,
544 chunk_from_thing(value));
545 }
546 value = htonl(entry->packets.sent);
547 message->add(message, RAT_ACCT_OUTPUT_PACKETS, chunk_from_thing(value));
548
549 value = htonl(entry->bytes.received);
550 message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value));
551 value = htonl(entry->bytes.received >> 32);
552 if (value)
553 {
554 message->add(message, RAT_ACCT_INPUT_GIGAWORDS,
555 chunk_from_thing(value));
556 }
557 value = htonl(entry->packets.received);
558 message->add(message, RAT_ACCT_INPUT_PACKETS, chunk_from_thing(value));
559
560 value = htonl(time_monotonic(NULL) - entry->created);
561 message->add(message, RAT_ACCT_SESSION_TIME, chunk_from_thing(value));
562
563
564 value = htonl(entry->cause);
565 message->add(message, RAT_ACCT_TERMINATE_CAUSE, chunk_from_thing(value));
566
567 if (!send_message(this, message))
568 {
569 eap_radius_handle_timeout(NULL);
570 }
571 message->destroy(message);
572 destroy_entry(entry);
573 }
574 }
575
576 METHOD(listener_t, alert, bool,
577 private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, alert_t alert,
578 va_list args)
579 {
580 radius_acct_terminate_cause_t cause;
581 entry_t *entry;
582
583 switch (alert)
584 {
585 case ALERT_IKE_SA_EXPIRED:
586 cause = ACCT_CAUSE_SESSION_TIMEOUT;
587 break;
588 case ALERT_RETRANSMIT_SEND_TIMEOUT:
589 cause = ACCT_CAUSE_LOST_SERVICE;
590 break;
591 default:
592 return TRUE;
593 }
594 this->mutex->lock(this->mutex);
595 entry = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa));
596 if (entry)
597 {
598 entry->cause = cause;
599 }
600 this->mutex->unlock(this->mutex);
601 return TRUE;
602 }
603
604 METHOD(listener_t, ike_updown, bool,
605 private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, bool up)
606 {
607 if (!up)
608 {
609 enumerator_t *enumerator;
610 child_sa_t *child_sa;
611
612 /* update usage for all children just before sending stop */
613 enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
614 while (enumerator->enumerate(enumerator, &child_sa))
615 {
616 update_usage(this, ike_sa, child_sa);
617 }
618 enumerator->destroy(enumerator);
619
620 send_stop(this, ike_sa);
621 }
622 return TRUE;
623 }
624
625 METHOD(listener_t, message_hook, bool,
626 private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
627 message_t *message, bool incoming, bool plain)
628 {
629 /* start accounting here, virtual IP now is set */
630 if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
631 !incoming && !message->get_request(message))
632 {
633 if (ike_sa->get_version(ike_sa) == IKEV1 &&
634 message->get_exchange_type(message) == TRANSACTION)
635 {
636 send_start(this, ike_sa);
637 }
638 if (ike_sa->get_version(ike_sa) == IKEV2 &&
639 message->get_exchange_type(message) == IKE_AUTH)
640 {
641 send_start(this, ike_sa);
642 }
643 }
644 return TRUE;
645 }
646
647 METHOD(listener_t, ike_rekey, bool,
648 private_eap_radius_accounting_t *this, ike_sa_t *old, ike_sa_t *new)
649 {
650 entry_t *entry;
651
652 this->mutex->lock(this->mutex);
653 entry = this->sessions->remove(this->sessions, old->get_id(old));
654 if (entry)
655 {
656 /* update IKE_SA identifier */
657 entry->id->destroy(entry->id);
658 entry->id = new->get_id(new);
659 entry->id = entry->id->clone(entry->id);
660 /* fire new interim update job, old gets invalid */
661 schedule_interim(this, entry);
662
663 entry = this->sessions->put(this->sessions, entry->id, entry);
664 if (entry)
665 {
666 destroy_entry(entry);
667 }
668 }
669 this->mutex->unlock(this->mutex);
670
671 return TRUE;
672 }
673
674 METHOD(listener_t, child_rekey, bool,
675 private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
676 child_sa_t *old, child_sa_t *new)
677 {
678 update_usage(this, ike_sa, old);
679
680 return TRUE;
681 }
682
683 METHOD(listener_t, child_updown, bool,
684 private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
685 child_sa_t *child_sa, bool up)
686 {
687 if (!up && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
688 {
689 update_usage(this, ike_sa, child_sa);
690 }
691 return TRUE;
692 }
693
694 METHOD(eap_radius_accounting_t, destroy, void,
695 private_eap_radius_accounting_t *this)
696 {
697 charon->bus->remove_listener(charon->bus, &this->public.listener);
698 singleton = NULL;
699 this->mutex->destroy(this->mutex);
700 this->sessions->destroy(this->sessions);
701 free(this);
702 }
703
704 /**
705 * See header
706 */
707 eap_radius_accounting_t *eap_radius_accounting_create()
708 {
709 private_eap_radius_accounting_t *this;
710
711 INIT(this,
712 .public = {
713 .listener = {
714 .alert = _alert,
715 .ike_updown = _ike_updown,
716 .ike_rekey = _ike_rekey,
717 .message = _message_hook,
718 .child_updown = _child_updown,
719 .child_rekey = _child_rekey,
720 },
721 .destroy = _destroy,
722 },
723 /* use system time as Session ID prefix */
724 .prefix = (u_int32_t)time(NULL),
725 .sessions = hashtable_create((hashtable_hash_t)hash,
726 (hashtable_equals_t)equals, 32),
727 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
728 );
729 if (lib->settings->get_bool(lib->settings,
730 "%s.plugins.eap-radius.station_id_with_port", TRUE, lib->ns))
731 {
732 this->station_id_fmt = "%#H";
733 }
734 else
735 {
736 this->station_id_fmt = "%H";
737 }
738 if (lib->settings->get_bool(lib->settings,
739 "%s.plugins.eap-radius.accounting", FALSE, lib->ns))
740 {
741 singleton = this;
742 charon->bus->add_listener(charon->bus, &this->public.listener);
743 }
744 this->acct_req_vip = lib->settings->get_bool(lib->settings,
745 "%s.plugins.eap-radius.accounting_requires_vip",
746 FALSE, lib->ns);
747
748 return &this->public;
749 }
750
751 /**
752 * See header
753 */
754 void eap_radius_accounting_start_interim(ike_sa_t *ike_sa, u_int32_t interval)
755 {
756 if (singleton)
757 {
758 entry_t *entry;
759
760 DBG1(DBG_CFG, "scheduling RADIUS Interim-Updates every %us", interval);
761 singleton->mutex->lock(singleton->mutex);
762 entry = get_or_create_entry(singleton, ike_sa);
763 entry->interim.interval = interval;
764 singleton->mutex->unlock(singleton->mutex);
765 }
766 }