diff options
author | Kozlov Dmitry <dima@server> | 2010-09-09 16:10:40 +0400 |
---|---|---|
committer | Kozlov Dmitry <dima@server> | 2010-09-09 16:13:25 +0400 |
commit | eac0adf4b2b038690c761a126cb3e55a888060df (patch) | |
tree | a286e779ad7f878bc7b8eaedb99f5a64f29b1632 /accel-pptpd | |
parent | 29b03dcfbd3b4783b0192e5f8c9bb6281acf44d5 (diff) | |
download | accel-ppp-eac0adf4b2b038690c761a126cb3e55a888060df.tar.gz accel-ppp-eac0adf4b2b038690c761a126cb3e55a888060df.zip |
radius: implemented DM/CoA extensions
Diffstat (limited to 'accel-pptpd')
-rw-r--r-- | accel-pptpd/accel-pptpd.conf | 1 | ||||
-rw-r--r-- | accel-pptpd/radius/CMakeLists.txt | 1 | ||||
-rw-r--r-- | accel-pptpd/radius/acct.c | 22 | ||||
-rw-r--r-- | accel-pptpd/radius/auth.c | 14 | ||||
-rw-r--r-- | accel-pptpd/radius/dict.c | 8 | ||||
-rw-r--r-- | accel-pptpd/radius/dictionary | 7 | ||||
-rw-r--r-- | accel-pptpd/radius/packet.c | 293 | ||||
-rw-r--r-- | accel-pptpd/radius/pd_coa.c | 199 | ||||
-rw-r--r-- | accel-pptpd/radius/radius.c | 100 | ||||
-rw-r--r-- | accel-pptpd/radius/radius.h | 48 | ||||
-rw-r--r-- | accel-pptpd/radius/req.c | 213 | ||||
-rw-r--r-- | accel-pptpd/triton/mempool.c | 4 | ||||
-rw-r--r-- | accel-pptpd/triton/triton.c | 32 | ||||
-rw-r--r-- | accel-pptpd/triton/triton.h | 1 | ||||
-rw-r--r-- | accel-pptpd/triton/triton_p.h | 9 |
15 files changed, 687 insertions, 265 deletions
diff --git a/accel-pptpd/accel-pptpd.conf b/accel-pptpd/accel-pptpd.conf index 2c7b33f..26bb27d 100644 --- a/accel-pptpd/accel-pptpd.conf +++ b/accel-pptpd/accel-pptpd.conf @@ -24,4 +24,5 @@ nas-ip-address=127.0.0.1 gw-ip-address=192.168.100.100 auth_server=127.0.0.1:1812,testing123 acct_server=127.0.0.1:1813,testing123 +pd_coa_secret=testing123 verbose=1 diff --git a/accel-pptpd/radius/CMakeLists.txt b/accel-pptpd/radius/CMakeLists.txt index 9655d91..ac8a3a9 100644 --- a/accel-pptpd/radius/CMakeLists.txt +++ b/accel-pptpd/radius/CMakeLists.txt @@ -6,6 +6,7 @@ SET(sources packet.c auth.c acct.c + pd_coa.c ) ADD_LIBRARY(radius SHARED ${sources}) diff --git a/accel-pptpd/radius/acct.c b/accel-pptpd/radius/acct.c index b342b33..53e5e38 100644 --- a/accel-pptpd/radius/acct.c +++ b/accel-pptpd/radius/acct.c @@ -37,18 +37,18 @@ static void req_set_stat(struct rad_req_t *req, struct ppp_t *ppp) return; } - rad_req_change_int(req, "Acct-Input-Octets", ifreq.stats.p.ppp_ibytes); - rad_req_change_int(req, "Acct-Output-Octets", ifreq.stats.p.ppp_obytes); - rad_req_change_int(req, "Acct-Input-Packets", ifreq.stats.p.ppp_ipackets); - rad_req_change_int(req, "Acct-Output-Packets", ifreq.stats.p.ppp_opackets); - rad_req_change_int(req, "Acct-Session-Time", time(NULL) - ppp->start_time); + rad_packet_change_int(req->pack, "Acct-Input-Octets", ifreq.stats.p.ppp_ibytes); + rad_packet_change_int(req->pack, "Acct-Output-Octets", ifreq.stats.p.ppp_obytes); + rad_packet_change_int(req->pack, "Acct-Input-Packets", ifreq.stats.p.ppp_ipackets); + rad_packet_change_int(req->pack, "Acct-Output-Packets", ifreq.stats.p.ppp_opackets); + rad_packet_change_int(req->pack, "Acct-Session-Time", time(NULL) - ppp->start_time); } static int rad_acct_read(struct triton_md_handler_t *h) { struct rad_req_t *req = container_of(h, typeof(*req), hnd); - req->reply = rad_packet_recv(h->fd); + req->reply = rad_packet_recv(h->fd, NULL); if (!req->reply) return 0; @@ -83,9 +83,9 @@ static void rad_acct_interim_update(struct triton_timer_t *t) if (rpd->acct_req->timeout.period) return; - rad_req_change_val(rpd->acct_req, "Acct-Status-Type", "Interim-Update", 4); + rad_packet_change_val(rpd->acct_req->pack, "Acct-Status-Type", "Interim-Update"); req_set_stat(rpd->acct_req, rpd->ppp); - req_set_RA(rpd->acct_req, conf_acct_server_secret); + req_set_RA(rpd->acct_req, conf_acct_secret); rad_req_send(rpd->acct_req); rpd->acct_req->timeout.period = conf_timeout * 1000; triton_timer_add(rpd->ppp->ctrl->ctx, &rpd->acct_req->timeout, 0); @@ -109,7 +109,7 @@ int rad_acct_start(struct radius_pd_t *rpd) //if (rad_req_add_str(rpd->acct_req, "Acct-Session-Id", rpd->ppp->sessionid, PPP_SESSIONID_LEN, 1)) // goto out_err; - if (req_set_RA(rpd->acct_req, conf_acct_server_secret)) + if (req_set_RA(rpd->acct_req, conf_acct_secret)) goto out_err; if (rad_req_send(rpd->acct_req)) @@ -155,9 +155,9 @@ void rad_acct_stop(struct radius_pd_t *rpd) if (rpd->acct_req->timeout.period) triton_timer_del(&rpd->acct_req->timeout); - rad_req_change_val(rpd->acct_req, "Acct-Status-Type", "Stop", 4); + rad_packet_change_val(rpd->acct_req->pack, "Acct-Status-Type", "Stop"); req_set_stat(rpd->acct_req, rpd->ppp); - req_set_RA(rpd->acct_req, conf_acct_server_secret); + req_set_RA(rpd->acct_req, conf_acct_secret); /// !!! rad_req_add_val(rpd->acct_req, "Acct-Terminate-Cause", ""); for(i = 0; i < conf_max_try; i++) { if (rad_req_send(rpd->acct_req)) diff --git a/accel-pptpd/radius/auth.c b/accel-pptpd/radius/auth.c index 98c7aa8..2415a05 100644 --- a/accel-pptpd/radius/auth.c +++ b/accel-pptpd/radius/auth.c @@ -56,11 +56,11 @@ int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args) if (!req) return PWDB_DENIED; - epasswd = encrypt_password(passwd, conf_auth_server_secret, req->RA, &epasswd_len); + epasswd = encrypt_password(passwd, conf_auth_secret, req->RA, &epasswd_len); if (!epasswd) goto out; - if (rad_req_add_str(req, "Password", (char*)epasswd, epasswd_len, 0)) { + if (rad_packet_add_octets(req->pack, "Password", epasswd, epasswd_len)) { free(epasswd); goto out; } @@ -97,12 +97,12 @@ int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list arg { struct rad_req_t *req; int i, r = PWDB_DENIED; - char chap_password[17]; + uint8_t chap_password[17]; int id = va_arg(args, int); - const uint8_t *challenge = va_arg(args, const uint8_t *); + uint8_t *challenge = va_arg(args, uint8_t *); int challenge_len = va_arg(args, int); - const uint8_t *response = va_arg(args, const uint8_t *); + uint8_t *response = va_arg(args, uint8_t *); chap_password[0] = id; memcpy(chap_password + 1, response, 16); @@ -114,11 +114,11 @@ int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list arg if (challenge_len == 16) memcpy(req->RA, challenge, 16); else { - if (rad_req_add_str(req, "CHAP-Challenge", (char*)challenge, challenge_len, 0)) + if (rad_packet_add_octets(req->pack, "CHAP-Challenge", challenge, challenge_len)) goto out; } - if (rad_req_add_str(req, "CHAP-Password", chap_password, 17, 0)) + if (rad_packet_add_octets(req->pack, "CHAP-Password", chap_password, 17)) goto out; for(i = 0; i < conf_max_try; i++) { diff --git a/accel-pptpd/radius/dict.c b/accel-pptpd/radius/dict.c index d76c2c3..4a0435a 100644 --- a/accel-pptpd/radius/dict.c +++ b/accel-pptpd/radius/dict.c @@ -42,10 +42,10 @@ static int split(char *buf, char **ptr) } buf = skip_word(buf); - if (*buf == '\n') + //if (*buf == '\n') *buf = 0; - else if (*buf) - return -1; + //else if (*buf) + // return -1; return 0; } @@ -124,6 +124,8 @@ int rad_dict_load(const char *fname) attr->type = ATTR_TYPE_DATE; else if (!strcmp(ptr[2], "ipaddr")) attr->type = ATTR_TYPE_IPADDR; + else if (!strcmp(ptr[2], "octets")) + attr->type = ATTR_TYPE_OCTETS; else { log_error("radius:%s:%i: unknown attribute type\n", fname, n); goto out_err; diff --git a/accel-pptpd/radius/dictionary b/accel-pptpd/radius/dictionary index 25896eb..223cc26 100644 --- a/accel-pptpd/radius/dictionary +++ b/accel-pptpd/radius/dictionary @@ -27,8 +27,8 @@ # Following are the proper new names. Use these. # ATTRIBUTE User-Name 1 string -ATTRIBUTE Password 2 string -ATTRIBUTE CHAP-Password 3 string +ATTRIBUTE Password 2 octets +ATTRIBUTE CHAP-Password 3 octets ATTRIBUTE NAS-IP-Address 4 ipaddr ATTRIBUTE NAS-Port-Id 5 integer ATTRIBUTE Service-Type 6 integer @@ -83,6 +83,7 @@ ATTRIBUTE Login-LAT-Port 63 integer ATTRIBUTE Connect-Info 77 string ATTRIBUTE Acct-Interim-Interval 85 integer +ATTRIBUTE Error-Cause 101 integer # # RFC3162 IPv6 attributes @@ -186,6 +187,7 @@ VALUE NAS-Port-Type Sync 1 VALUE NAS-Port-Type ISDN 2 VALUE NAS-Port-Type ISDN-V120 3 VALUE NAS-Port-Type ISDN-V110 4 +VALUE NAS-Port-Type Virtual 5 # Acct Terminate Causes, available in 3.3.2 and later @@ -239,4 +241,3 @@ VALUE Add-Port-To-IP-Address Yes 1 #VALUE Server-Config Password-Expiration 30 #VALUE Server-Config Password-Warning 5 - diff --git a/accel-pptpd/radius/packet.c b/accel-pptpd/radius/packet.c index e88e6e8..dcc1053 100644 --- a/accel-pptpd/radius/packet.c +++ b/accel-pptpd/radius/packet.c @@ -39,7 +39,7 @@ void print_buf(uint8_t *buf,int size) int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA) { - struct rad_req_attr_t *attr; + struct rad_attr_t *attr; uint8_t *ptr; if (pack->buf) @@ -65,6 +65,7 @@ int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA) case ATTR_TYPE_INTEGER: *(uint32_t*)ptr = htonl(attr->val.integer); break; + case ATTR_TYPE_OCTETS: case ATTR_TYPE_STRING: memcpy(ptr, attr->val.string, attr->len); break; @@ -85,13 +86,14 @@ int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA) return 0; } -struct rad_packet_t *rad_packet_recv(int fd) +struct rad_packet_t *rad_packet_recv(int fd, struct sockaddr_in *addr) { struct rad_packet_t *pack; - struct rad_req_attr_t *attr; + struct rad_attr_t *attr; struct rad_dict_attr_t *da; uint8_t *ptr; int n, id, len; + socklen_t addr_len = sizeof(*addr); pack = rad_packet_alloc(0); if (!pack) @@ -104,7 +106,10 @@ struct rad_packet_t *rad_packet_recv(int fd) } while (1) { - n = read(fd, pack->buf, REQ_LENGTH_MAX); + if (addr) + n = recvfrom(fd, pack->buf, REQ_LENGTH_MAX, 0, addr, &addr_len); + else + n = read(fd, pack->buf, REQ_LENGTH_MAX); if (n < 0) { if (errno == EINTR) continue; @@ -164,6 +169,15 @@ struct rad_packet_t *rad_packet_recv(int fd) memcpy(attr->val.string, ptr, len); attr->val.string[len] = 0; break; + case ATTR_TYPE_OCTETS: + attr->val.octets = malloc(len); + if (!attr->val.octets) { + log_error("radius:packet: out of memory\n"); + free(attr); + goto out_err; + } + memcpy(attr->val.octets, ptr, len); + break; case ATTR_TYPE_DATE: case ATTR_TYPE_INTEGER: attr->val.integer = ntohl(*(uint32_t*)ptr); @@ -188,15 +202,15 @@ out_err: void rad_packet_free(struct rad_packet_t *pack) { - struct rad_req_attr_t *attr; + struct rad_attr_t *attr; if (pack->buf) free(pack->buf); while(!list_empty(&pack->attrs)) { attr = list_entry(pack->attrs.next, typeof(*attr), entry); - if (attr->attr->type == ATTR_TYPE_STRING) - free((char*)attr->val.string); + if (attr->attr->type == ATTR_TYPE_STRING || attr->attr->type == ATTR_TYPE_OCTETS) + free(attr->val.string); list_del(&attr->entry); free(attr); } @@ -206,7 +220,7 @@ void rad_packet_free(struct rad_packet_t *pack) void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, ...)) { - struct rad_req_attr_t *attr; + struct rad_attr_t *attr; struct rad_dict_value_t *val; print("[RADIUS "); @@ -229,6 +243,24 @@ void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, case CODE_ACCOUNTING_RESPONSE: printf("Accounting-Response"); break; + case CODE_DISCONNECT_REQUEST: + printf("Disconnect-Request"); + break; + case CODE_DISCONNECT_ACK: + printf("Disconnect-ACK"); + break; + case CODE_DISCONNECT_NAK: + printf("Disconnect-NAK"); + break; + case CODE_COA_REQUEST: + printf("CoA-Request"); + break; + case CODE_COA_ACK: + printf("CoA-ACK"); + break; + case CODE_COA_NAK: + printf("CoA-NAK"); + break; default: print("Unknown (%i)", pack->code); } @@ -236,25 +268,238 @@ void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, list_for_each_entry(attr, &pack->attrs, entry) { print(" <%s ", attr->attr->name); - if (attr->printable) { - switch (attr->attr->type) { - case ATTR_TYPE_INTEGER: - val = rad_dict_find_val(attr->attr, attr->val); - if (val) - print("%s", val->name); - else - print("%i", attr->val.integer); - break; - case ATTR_TYPE_STRING: - print("\"%s\"", attr->val.string); - break; - case ATTR_TYPE_IPADDR: - print("%i.%i.%i.%i", attr->val.ipaddr & 0xff, (attr->val.ipaddr >> 8) & 0xff, (attr->val.ipaddr >> 16) & 0xff, (attr->val.ipaddr >> 24) & 0xff); - break; - } + switch (attr->attr->type) { + case ATTR_TYPE_INTEGER: + val = rad_dict_find_val(attr->attr, attr->val); + if (val) + print("%s", val->name); + else + print("%i", attr->val.integer); + break; + case ATTR_TYPE_STRING: + print("\"%s\"", attr->val.string); + break; + case ATTR_TYPE_IPADDR: + print("%i.%i.%i.%i", attr->val.ipaddr & 0xff, (attr->val.ipaddr >> 8) & 0xff, (attr->val.ipaddr >> 16) & 0xff, (attr->val.ipaddr >> 24) & 0xff); + break; } print(">"); } print("]\n"); } +int rad_packet_add_int(struct rad_packet_t *pack, const char *name, int val) +{ + struct rad_attr_t *ra; + struct rad_dict_attr_t *attr; + + if (pack->len + 2 + 4 >= REQ_LENGTH_MAX) + return -1; + + attr = rad_dict_find_attr(name); + if (!attr) + return -1; + + ra = malloc(sizeof(*ra)); + if (!ra) + return -1; + + ra->attr = attr; + ra->len = 4; + ra->val.integer = val; + list_add_tail(&ra->entry, &pack->attrs); + pack->len += 2 + 4; + + return 0; +} + +int rad_packet_change_int(struct rad_packet_t *pack, const char *name, int val) +{ + struct rad_attr_t *ra; + + ra = rad_packet_find_attr(pack, name); + if (!ra) + return -1; + + ra->val.integer = val; + + return 0; +} + +int rad_packet_add_octets(struct rad_packet_t *pack, const char *name, uint8_t *val, int len) +{ + struct rad_attr_t *ra; + struct rad_dict_attr_t *attr; + + if (pack->len + 2 + len >= REQ_LENGTH_MAX) + return -1; + + attr = rad_dict_find_attr(name); + if (!attr) + return -1; + + ra = malloc(sizeof(*ra)); + if (!ra) { + log_error("radius: out of memory\n"); + return -1; + } + + ra->attr = attr; + ra->len = len; + ra->val.octets = malloc(len); + if (!ra->val.octets) { + log_error("radius: out of memory\n"); + free(ra); + return -1; + } + memcpy(ra->val.octets, val, len); + list_add_tail(&ra->entry, &pack->attrs); + pack->len += 2 + len; + + return 0; +} +int rad_packet_add_str(struct rad_packet_t *pack, const char *name, const char *val, int len) +{ + struct rad_attr_t *ra; + struct rad_dict_attr_t *attr; + + if (pack->len + 2 + len >= REQ_LENGTH_MAX) + return -1; + + attr = rad_dict_find_attr(name); + if (!attr) + return -1; + + ra = malloc(sizeof(*ra)); + if (!ra) { + log_error("radius: out of memory\n"); + return -1; + } + + ra->attr = attr; + ra->len = len; + ra->val.string = malloc(len+1); + if (!ra->val.string) { + log_error("radius: out of memory\n"); + free(ra); + return -1; + } + memcpy(ra->val.string, val, len); + ra->val.string[len] = 0; + list_add_tail(&ra->entry, &pack->attrs); + pack->len += 2 + len; + + return 0; +} + +int rad_packet_change_str(struct rad_packet_t *pack, const char *name, const char *val, int len) +{ + struct rad_attr_t *ra; + + ra = rad_packet_find_attr(pack, name); + if (!ra) + return -1; + + if (ra->len != len) { + if (pack->len - ra->len + len >= REQ_LENGTH_MAX) + return -1; + + ra->val.string = realloc(ra->val.string, len + 1); + if (!ra->val.string) { + log_error("radius: out of memory\n"); + return -1; + } + + pack->len += len - ra->len; + ra->len = len; + } + + memcpy(ra->val.string, val, len); + ra->val.string[len] = 0; + + return 0; +} + +int rad_packet_add_val(struct rad_packet_t *pack, const char *name, const char *val) +{ + struct rad_attr_t *ra; + struct rad_dict_attr_t *attr; + struct rad_dict_value_t *v; + + if (pack->len + 2 + 4 >= REQ_LENGTH_MAX) + return -1; + + attr = rad_dict_find_attr(name); + if (!attr) + return -1; + + v = rad_dict_find_val_name(attr, val); + if (!v) + return -1; + + ra = malloc(sizeof(*ra)); + if (!ra) + return -1; + + ra->attr = attr; + ra->len = 4; + ra->val = v->val; + list_add_tail(&ra->entry, &pack->attrs); + pack->len += 2 + 4; + + return 0; +} + +int rad_packet_change_val(struct rad_packet_t *pack, const char *name, const char *val) +{ + struct rad_attr_t *ra; + struct rad_dict_value_t *v; + + ra = rad_packet_find_attr(pack, name); + if (!ra) + return -1; + + v = rad_dict_find_val_name(ra->attr, val); + if (!v) + return -1; + + ra->val = v->val; + + return 0; +} + +struct rad_attr_t *rad_packet_find_attr(struct rad_packet_t *pack, const char *name) +{ + struct rad_attr_t *ra; + + list_for_each_entry(ra, &pack->attrs, entry) + if (!strcmp(ra->attr->name, name)) + return ra; + + return NULL; +} + +int rad_packet_send(struct rad_packet_t *pack, int fd, struct sockaddr_in *addr) +{ + int n; + + while (1) { + if (addr) + n = sendto(fd, pack->buf, pack->len, 0, addr, sizeof(*addr)); + else + n = write(fd, pack->buf, pack->len); + if (n < 0) { + if (errno == EINTR) + continue; + log_error("radius:write: %s\n", strerror(errno)); + return -1; + } else if (n != pack->len) { + log_error("radius:write: short write %i, excpected %i\n", n, pack->len); + return -1; + } + break; + } + + return 0; +} + diff --git a/accel-pptpd/radius/pd_coa.c b/accel-pptpd/radius/pd_coa.c new file mode 100644 index 0000000..b19575c --- /dev/null +++ b/accel-pptpd/radius/pd_coa.c @@ -0,0 +1,199 @@ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <openssl/md5.h> + +#include "triton.h" +#include "log.h" + +#include "radius.h" + +#define PD_COA_PORT 3799 + +struct pd_coa_serv_t +{ + struct triton_context_t ctx; + struct triton_md_handler_t hnd; +}; + +static int pd_coa_check_RA(struct rad_packet_t *pack, const char *secret) +{ + uint8_t RA[16]; + MD5_CTX ctx; + + memset(RA, 0, 16); + + MD5_Init(&ctx); + MD5_Update(&ctx, pack->buf, 4); + MD5_Update(&ctx, RA, 16); + MD5_Update(&ctx, pack->buf + 20, pack->len - 20); + MD5_Update(&ctx, secret, strlen(secret)); + MD5_Final(RA, &ctx); + + return memcmp(RA, pack->buf + 4, 16); +} + +static void pd_coa_set_RA(struct rad_packet_t *pack, const char *secret) +{ + MD5_CTX ctx; + + MD5_Init(&ctx); + MD5_Update(&ctx, pack->buf, pack->len); + MD5_Update(&ctx, secret, strlen(secret)); + MD5_Final(pack->buf + 4, &ctx); +} + +static void disconnect_request(struct radius_pd_t *rpd) +{ + rad_packet_free(rpd->pd_coa_req); + rpd->pd_coa_req = NULL; + + ppp_terminate(rpd->ppp, 0); +} + +static void coa_request(struct radius_pd_t *rpd) +{ + rad_packet_free(rpd->pd_coa_req); + rpd->pd_coa_req = NULL; + +/// TODO: CoA handling +} + +static int pd_coa_read(struct triton_md_handler_t *h) +{ + struct rad_packet_t *pack; + struct rad_packet_t *reply = NULL; + struct radius_pd_t *rpd; + int err_code; + uint8_t RA[16]; + struct sockaddr_in addr; + + + pack = rad_packet_recv(h->fd, &addr); + if (!pack) + return 0; + + if (pack->code != CODE_DISCONNECT_REQUEST && pack->code != CODE_COA_REQUEST) { + log_warn("radius:pd_coa: unexpected code (%i) received\n", pack->code); + goto out_err_no_reply; + } + + if (pd_coa_check_RA(pack, conf_pd_coa_secret)) { + log_warn("radius:pd_coa: RA validation failed\n"); + goto out_err_no_reply; + } + + memcpy(RA, pack->buf + 4, sizeof(RA)); + + if (conf_verbose) { + log_debug("recv "); + rad_packet_print(pack, log_debug); + } + + if (rad_check_nas_pack(pack)) { + log_warn("radius:pd_coa: NAS identification failed\n"); + err_code = 403; + goto out_err; + } + + rpd = rad_find_session_pack(pack); + if (!rpd) { + log_warn("radius:pd_coa: session not found\n"); + err_code = 503; + goto out_err; + } + + rpd->pd_coa_req = pack; + + if (pack->code == CODE_DISCONNECT_REQUEST) + triton_context_call(rpd->ppp->ctrl->ctx, (void (*)(void *))disconnect_request, rpd); + else + triton_context_call(rpd->ppp->ctrl->ctx, (void (*)(void *))coa_request, rpd); + + pthread_mutex_unlock(&rpd->lock); + + reply = rad_packet_alloc(pack->code == CODE_COA_REQUEST ? CODE_COA_ACK : CODE_DISCONNECT_ACK); + reply->id = pack->id; + if (rad_packet_build(reply, RA)) + goto out_err_no_reply; + pd_coa_set_RA(reply, conf_pd_coa_secret); + if (conf_verbose) { + log_debug("send "); + rad_packet_print(reply, log_debug); + } + rad_packet_send(reply, h->fd, &addr); + rad_packet_free(reply); + + return 0; + +out_err: + reply = rad_packet_alloc(pack->code == CODE_COA_REQUEST ? CODE_COA_NAK : CODE_DISCONNECT_NAK); + rad_packet_add_int(reply, "Error-Cause", err_code); + reply->id = pack->id; + if (rad_packet_build(reply, RA)) + goto out_err_no_reply; + pd_coa_set_RA(reply, conf_pd_coa_secret); + if (conf_verbose) { + log_debug("send "); + rad_packet_print(reply, log_debug); + } + rad_packet_send(reply, h->fd, &addr); + +out_err_no_reply: + rad_packet_free(pack); + if (reply) + rad_packet_free(reply); + return 0; +} + +static void pd_coa_close(struct triton_context_t *ctx) +{ + struct pd_coa_serv_t *serv = container_of(ctx, typeof(*serv), ctx); + triton_md_unregister_handler(&serv->hnd); + close(serv->hnd.fd); +} + +static struct pd_coa_serv_t serv = { + .ctx.close = pd_coa_close, + .hnd.read = pd_coa_read, +}; + +static void __init init(void) +{ + struct sockaddr_in addr; + + serv.hnd.fd = socket (PF_INET, SOCK_DGRAM, 0); + if (serv.hnd.fd < 0) { + log_error("radius:pd_coa: socket: %s\n", strerror(errno)); + return; + } + addr.sin_family = AF_INET; + addr.sin_port = htons (PD_COA_PORT); + if (conf_nas_ip_address) + addr.sin_addr.s_addr = inet_addr(conf_nas_ip_address); + else + addr.sin_addr.s_addr = htonl (INADDR_ANY); + if (bind (serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { + log_error("radius:pd_coa: bind: %s\n", strerror(errno)); + close(serv.hnd.fd); + return; + } + + if (fcntl(serv.hnd.fd, F_SETFL, O_NONBLOCK)) { + log_error("radius:pd_coa: failed to set nonblocking mode: %s\n", strerror(errno)); + close(serv.hnd.fd); + return; + } + + triton_context_register(&serv.ctx); + triton_md_register_handler(&serv.ctx, &serv.hnd); + triton_md_enable_handler(&serv.hnd, MD_MODE_READ); +} diff --git a/accel-pptpd/radius/radius.c b/accel-pptpd/radius/radius.c index 89491b3..de64f6b 100644 --- a/accel-pptpd/radius/radius.c +++ b/accel-pptpd/radius/radius.c @@ -25,17 +25,21 @@ int conf_verbose = 0; char *conf_auth_server; int conf_auth_server_port = 1812; -char *conf_auth_server_secret; +char *conf_auth_secret; char *conf_acct_server; int conf_acct_server_port = 1813; -char *conf_acct_server_secret; +char *conf_acct_secret; +char *conf_pd_coa_secret; + +static LIST_HEAD(sessions); +static pthread_rwlock_t sessions_lock = PTHREAD_RWLOCK_INITIALIZER; static struct ppp_notified_t notified; void rad_proc_attrs(struct rad_req_t *req) { - struct rad_req_attr_t *attr; + struct rad_attr_t *attr; list_for_each_entry(attr, &req->reply->attrs, entry) { if (!strcmp(attr->attr->name, "Framed-IP-Address")) @@ -102,7 +106,12 @@ static void ppp_starting(struct ppp_notified_t *n, struct ppp_t *ppp) memset(pd, 0, sizeof(*pd)); pd->pd.key = n; pd->ppp = ppp; + pthread_mutex_init(&pd->lock, NULL); list_add_tail(&pd->pd.entry, &ppp->pd_list); + + pthread_rwlock_wrlock(&sessions_lock); + list_add_tail(&pd->entry, &sessions); + pthread_rwlock_unlock(&sessions_lock); } static void ppp_started(struct ppp_notified_t *n, struct ppp_t *ppp) @@ -122,6 +131,15 @@ static void ppp_finished(struct ppp_notified_t *n, struct ppp_t *ppp) { struct radius_pd_t *rpd = find_pd(ppp); + pthread_rwlock_wrlock(&sessions_lock); + pthread_mutex_lock(&rpd->lock); + list_del(&rpd->entry); + pthread_mutex_unlock(&rpd->lock); + pthread_rwlock_unlock(&sessions_lock); + + if (rpd->pd_coa_req) + rad_packet_free(rpd->pd_coa_req); + list_del(&rpd->pd.entry); free(rpd); } @@ -142,6 +160,74 @@ struct radius_pd_t *find_pd(struct ppp_t *ppp) } +struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, int port_id, in_addr_t ipaddr) +{ + struct radius_pd_t *rpd; + + pthread_rwlock_rdlock(&sessions_lock); + list_for_each_entry(rpd, &sessions, entry) { + if (sessionid && strcmp(sessionid, rpd->ppp->sessionid)) + continue; + if (username && strcmp(username, rpd->ppp->username)) + continue; + if (port_id >= 0 && port_id != rpd->ppp->unit_idx) + continue; + if (ipaddr && ipaddr != rpd->ipaddr) + continue; + pthread_mutex_lock(&rpd->lock); + pthread_rwlock_unlock(&sessions_lock); + return rpd; + } + pthread_rwlock_unlock(&sessions_lock); + return NULL; +} + +struct radius_pd_t *rad_find_session_pack(struct rad_packet_t *pack) +{ + struct rad_attr_t *attr; + const char *sessionid = NULL; + const char *username = NULL; + int port_id = -1; + in_addr_t ipaddr = 0; + + list_for_each_entry(attr, &pack->attrs, entry) { + if (!strcmp(attr->attr->name, "Acct-Session-Id")) + sessionid = attr->val.string; + else if (!strcmp(attr->attr->name, "User-Name")) + username = attr->val.string; + else if (!strcmp(attr->attr->name, "NAS-Port-Id")) + port_id = attr->val.integer; + else if (!strcmp(attr->attr->name, "Framed-IP-Address")) + ipaddr = attr->val.ipaddr; + } + + if (username && !sessionid) + return NULL; + + return rad_find_session(sessionid, username, port_id, ipaddr); +} + +int rad_check_nas_pack(struct rad_packet_t *pack) +{ + struct rad_attr_t *attr; + const char *ident = NULL; + in_addr_t ipaddr = 0; + + list_for_each_entry(attr, &pack->attrs, entry) { + if (!strcmp(attr->attr->name, "NAS-Identifier")) + ident = attr->val.string; + else if (!strcmp(attr->attr->name, "NAS-IP-Address")) + ipaddr = attr->val.ipaddr; + } + + if (conf_nas_identifier && (!ident || strcmp(conf_nas_identifier, ident))) + return -1; + if (conf_nas_ip_address && inet_addr(conf_nas_ip_address) != ipaddr) + return -1; + + return 0; +} + static struct ipdb_t ipdb = { .get = get_ip, }; @@ -211,17 +297,21 @@ static void __init radius_init(void) if (!opt) { log_error("radius: auth_server not specified\n"); _exit(EXIT_FAILURE); - } else if (parse_server(opt, &conf_auth_server, &conf_auth_server_port, &conf_auth_server_secret)) { + } else if (parse_server(opt, &conf_auth_server, &conf_auth_server_port, &conf_auth_secret)) { log_error("radius: failed to parse auth_server\n"); _exit(EXIT_FAILURE); } opt = conf_get_opt("radius", "acct_server"); - if (opt && parse_server(opt, &conf_acct_server, &conf_acct_server_port, &conf_acct_server_secret)) { + if (opt && parse_server(opt, &conf_acct_server, &conf_acct_server_port, &conf_acct_secret)) { log_error("radius: failed to parse acct_server\n"); _exit(EXIT_FAILURE); } + opt = conf_get_opt("radius", "pd_coa_secret"); + if (opt) + conf_pd_coa_secret = opt; + opt = conf_get_opt("radius", "dictionary"); if (!opt) { fprintf(stderr, "radius: dictionary not specified\n"); diff --git a/accel-pptpd/radius/radius.h b/accel-pptpd/radius/radius.h index c167151..9728a4a 100644 --- a/accel-pptpd/radius/radius.h +++ b/accel-pptpd/radius/radius.h @@ -3,6 +3,8 @@ #include <stdint.h> #include <netinet/in.h> +#include <pthread.h> + #include "triton.h" #include "ppp.h" @@ -10,25 +12,35 @@ #define ATTR_TYPE_INTEGER 0 #define ATTR_TYPE_STRING 1 -#define ATTR_TYPE_DATE 2 -#define ATTR_TYPE_IPADDR 3 +#define ATTR_TYPE_OCTETS 2 +#define ATTR_TYPE_DATE 3 +#define ATTR_TYPE_IPADDR 4 #define CODE_ACCESS_REQUEST 1 #define CODE_ACCESS_ACCEPT 2 #define CODE_ACCESS_REJECT 3 #define CODE_ACCESS_CHALLENGE 11 -#define CODE_ACCOUNTING_REQUEST 4 +#define CODE_ACCOUNTING_REQUEST 4 #define CODE_ACCOUNTING_RESPONSE 5 +#define CODE_DISCONNECT_REQUEST 40 +#define CODE_DISCONNECT_ACK 41 +#define CODE_DISCONNECT_NAK 42 +#define CODE_COA_REQUEST 43 +#define CODE_COA_ACK 44 +#define CODE_COA_NAK 45 struct radius_pd_t { + struct list_head entry; struct ppp_pd_t pd; struct ppp_t *ppp; + pthread_mutex_t lock; struct rad_req_t *acct_req; struct triton_timer_t acct_interim_timer; + struct rad_packet_t *pd_coa_req; in_addr_t ipaddr; int acct_interim_interval; @@ -38,6 +50,7 @@ typedef union { int integer; char *string; + uint8_t *octets; time_t date; in_addr_t ipaddr; } rad_value_t; @@ -63,14 +76,13 @@ struct rad_dict_attr_t struct list_head values; }; -struct rad_req_attr_t +struct rad_attr_t { struct list_head entry; struct rad_dict_attr_t *attr; //struct rad_dict_value_t *val; rad_value_t val; int len; - int printable:1; }; struct rad_packet_t @@ -103,11 +115,16 @@ extern char *conf_nas_identifier; extern char *conf_nas_ip_address; extern char *conf_gw_ip_address; extern char *conf_auth_server; -extern char *conf_auth_server_secret; +extern char *conf_auth_secret; extern int conf_auth_server_port; extern char *conf_acct_server; -extern char *conf_acct_server_secret; +extern char *conf_acct_secret; extern int conf_acct_server_port; +extern char *conf_pd_coa_secret; + +int rad_check_nas_pack(struct rad_packet_t *pack); +struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, int port_id, in_addr_t ipaddr); +struct radius_pd_t *rad_find_session_pack(struct rad_packet_t *pack); int rad_dict_load(const char *fname); void rad_dict_free(struct rad_dict_t *dict); @@ -121,18 +138,21 @@ int rad_req_acct_fill(struct rad_req_t *); void rad_req_free(struct rad_req_t *); int rad_req_send(struct rad_req_t *); int rad_req_wait(struct rad_req_t *, int); -struct rad_req_attr_t *rad_req_find_attr(struct rad_req_t *req, const char *name); -int rad_req_add_int(struct rad_req_t *req, const char *name, int val); -int rad_req_add_val(struct rad_req_t *req, const char *name, const char *val, int len); -int rad_req_add_str(struct rad_req_t *req, const char *name, const char *val, int len, int printable); -int rad_req_change_int(struct rad_req_t *req, const char *name, int val); -int rad_req_change_val(struct rad_req_t *req, const char *name, const char *val, int len); + +struct rad_attr_t *rad_packet_find_attr(struct rad_packet_t *pack, const char *name); +int rad_packet_add_int(struct rad_packet_t *pack, const char *name, int val); +int rad_packet_add_val(struct rad_packet_t *pack, const char *name, const char *val); +int rad_packet_add_str(struct rad_packet_t *pack, const char *name, const char *val, int len); +int rad_packet_add_octets(struct rad_packet_t *pack, const char *name, uint8_t *val, int len); +int rad_packet_change_int(struct rad_packet_t *pack, const char *name, int val); +int rad_packet_change_val(struct rad_packet_t *pack, const char *name, const char *val); struct rad_packet_t *rad_packet_alloc(int code); int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA); -struct rad_packet_t *rad_packet_recv(int fd); +struct rad_packet_t *rad_packet_recv(int fd, struct sockaddr_in *addr); void rad_packet_free(struct rad_packet_t *); void rad_packet_print(struct rad_packet_t *pack, void (*print)(const char *fmt, ...)); +int rad_packet_send(struct rad_packet_t *pck, int fd, struct sockaddr_in *addr); struct radius_pd_t *find_pd(struct ppp_t *ppp); void rad_proc_attrs(struct rad_req_t *req); diff --git a/accel-pptpd/radius/req.c b/accel-pptpd/radius/req.c index 3d71bf8..40397a8 100644 --- a/accel-pptpd/radius/req.c +++ b/accel-pptpd/radius/req.c @@ -43,18 +43,18 @@ struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *u if (!req->pack) goto out_err; - if (rad_req_add_str(req, "User-Name", username, strlen(username), 1)) + if (rad_packet_add_str(req->pack, "User-Name", username, strlen(username))) goto out_err; if (conf_nas_identifier) - if (rad_req_add_str(req, "NAS-Identifier", conf_nas_identifier, strlen(conf_nas_identifier), 1)) + if (rad_packet_add_str(req->pack, "NAS-Identifier", conf_nas_identifier, strlen(conf_nas_identifier))) goto out_err; - if (rad_req_add_int(req, "NAS-Port-Id", rpd->ppp->unit_idx)) + if (rad_packet_add_int(req->pack, "NAS-Port-Id", rpd->ppp->unit_idx)) goto out_err; - if (rad_req_add_val(req, "NAS-Port-Type", "Sync", 4)) + if (rad_packet_add_val(req->pack, "NAS-Port-Type", "Virtual")) goto out_err; - if (rad_req_add_val(req, "Service-Type", "Framed-User", 4)) + if (rad_packet_add_val(req->pack, "Service-Type", "Framed-User")) goto out_err; - if (rad_req_add_val(req, "Framed-Protocol", "PPP", 4)) + if (rad_packet_add_val(req->pack, "Framed-Protocol", "PPP")) goto out_err; return req; @@ -71,19 +71,19 @@ int rad_req_acct_fill(struct rad_req_t *req) memset(req->RA, 0, sizeof(req->RA)); - if (rad_req_add_val(req, "Acct-Status-Type", "Start", 4)) + if (rad_packet_add_val(req->pack, "Acct-Status-Type", "Start")) return -1; - if (rad_req_add_str(req, "Acct-Session-Id", req->rpd->ppp->sessionid, PPP_SESSIONID_LEN, 1)) + if (rad_packet_add_str(req->pack, "Acct-Session-Id", req->rpd->ppp->sessionid, PPP_SESSIONID_LEN)) return -1; - if (rad_req_add_int(req, "Acct-Session-Time", 0)) + if (rad_packet_add_int(req->pack, "Acct-Session-Time", 0)) return -1; - if (rad_req_add_int(req, "Acct-Input-Octets", 0)) + if (rad_packet_add_int(req->pack, "Acct-Input-Octets", 0)) return -1; - if (rad_req_add_int(req, "Acct-Output-Octets", 0)) + if (rad_packet_add_int(req->pack, "Acct-Output-Octets", 0)) return -1; - if (rad_req_add_int(req, "Acct-Input-Packets", 0)) + if (rad_packet_add_int(req->pack, "Acct-Input-Packets", 0)) return -1; - if (rad_req_add_int(req, "Acct-Output-Packets", 0)) + if (rad_packet_add_int(req->pack, "Acct-Output-Packets", 0)) return -1; return 0; @@ -144,8 +144,6 @@ out_err: int rad_req_send(struct rad_req_t *req) { - int n; - if (req->hnd.fd == -1 && make_socket(req)) return -1; @@ -157,20 +155,7 @@ int rad_req_send(struct rad_req_t *req) rad_packet_print(req->pack, log_debug); } - while (1) { - n = write(req->hnd.fd, req->pack->buf, req->pack->len); - //n = sendto(req->hnd.fd, req->pack->buf, req->pack->len, 0, &addr, sizeof(addr)); - if (n < 0) { - if (errno == EINTR) - continue; - log_error("radius:write: %s\n", strerror(errno)); - goto out_err; - } else if (n != req->pack->len) { - log_error("radius:write: short write %i, excpected %i\n", n, req->pack->len); - goto out_err; - } - break; - } + rad_packet_send(req->pack, req->hnd.fd, NULL); return 0; @@ -180,174 +165,6 @@ out_err: return -1; } -int rad_req_add_int(struct rad_req_t *req, const char *name, int val) -{ - struct rad_req_attr_t *ra; - struct rad_dict_attr_t *attr; - - if (req->pack->len + 2 + 4 >= REQ_LENGTH_MAX) - return -1; - - attr = rad_dict_find_attr(name); - if (!attr) - return -1; - - ra = malloc(sizeof(*ra)); - if (!ra) - return -1; - - ra->attr = attr; - ra->len = 4; - ra->val.integer = val; - ra->printable = 1; - list_add_tail(&ra->entry, &req->pack->attrs); - req->pack->len += 2 + 4; - - return 0; -} - -int rad_req_change_int(struct rad_req_t *req, const char *name, int val) -{ - struct rad_req_attr_t *ra; - - ra = rad_req_find_attr(req, name); - if (!ra) - return -1; - - ra->val.integer = val; - - return 0; -} - -int rad_req_add_str(struct rad_req_t *req, const char *name, const char *val, int len, int printable) -{ - struct rad_req_attr_t *ra; - struct rad_dict_attr_t *attr; - - if (req->pack->len + 2 + len >= REQ_LENGTH_MAX) - return -1; - - attr = rad_dict_find_attr(name); - if (!attr) - return -1; - - ra = malloc(sizeof(*ra)); - if (!ra) { - log_error("radius: aout of memory\n"); - return -1; - } - - ra->attr = attr; - ra->len = len; - ra->val.string = malloc(len+1); - if (!ra->val.string) { - log_error("radius: out of memory\n"); - free(ra); - return -1; - } - memcpy(ra->val.string, val, len); - ra->val.string[len] = 0; - ra->printable = printable; - list_add_tail(&ra->entry, &req->pack->attrs); - req->pack->len += 2 + len; - - return 0; -} - -int rad_req_change_str(struct rad_req_t *req, const char *name, const char *val, int len) -{ - struct rad_req_attr_t *ra; - - ra = rad_req_find_attr(req, name); - if (!ra) - return -1; - - if (ra->len != len) { - if (req->pack->len - ra->len + len >= REQ_LENGTH_MAX) - return -1; - - ra->val.string = realloc(ra->val.string, len + 1); - if (!ra->val.string) { - log_error("radius: out of memory\n"); - return -1; - } - - req->pack->len += len - ra->len; - ra->len = len; - } - - memcpy(ra->val.string, val, len); - ra->val.string[len] = 0; - - return 0; -} - -int rad_req_add_val(struct rad_req_t *req, const char *name, const char *val, int len) -{ - struct rad_req_attr_t *ra; - struct rad_dict_attr_t *attr; - struct rad_dict_value_t *v; - - if (req->pack->len + 2 + len >= REQ_LENGTH_MAX) - return -1; - - attr = rad_dict_find_attr(name); - if (!attr) - return -1; - - v = rad_dict_find_val_name(attr, val); - if (!v) - return -1; - - ra = malloc(sizeof(*ra)); - if (!ra) - return -1; - - ra->attr = attr; - ra->len = len; - ra->val = v->val; - ra->printable = 1; - list_add_tail(&ra->entry, &req->pack->attrs); - req->pack->len += 2 + len; - - return 0; -} - -int rad_req_change_val(struct rad_req_t *req, const char *name, const char *val, int len) -{ - struct rad_req_attr_t *ra; - struct rad_dict_value_t *v; - - ra = rad_req_find_attr(req, name); - if (!ra) - return -1; - - v = rad_dict_find_val_name(ra->attr, val); - if (!v) - return -1; - - if (req->pack->len - ra->len + len >= REQ_LENGTH_MAX) - return -1; - - req->pack->len += len - ra->len; - - ra->len = len; - ra->val = v->val; - - return 0; -} - -struct rad_req_attr_t *rad_req_find_attr(struct rad_req_t *req, const char *name) -{ - struct rad_req_attr_t *ra; - - list_for_each_entry(ra, &req->pack->attrs, entry) - if (!strcmp(ra->attr->name, name)) - return ra; - - return NULL; -} - static void req_wakeup(struct rad_req_t *req) { triton_context_wakeup(req->rpd->ppp->ctrl->ctx); @@ -359,7 +176,7 @@ static int rad_req_read(struct triton_md_handler_t *h) { struct rad_req_t *req = container_of(h, typeof(*req), hnd); - req->reply = rad_packet_recv(h->fd); + req->reply = rad_packet_recv(h->fd, NULL); req_wakeup(req); return 0; diff --git a/accel-pptpd/triton/mempool.c b/accel-pptpd/triton/mempool.c index 973fec5..dacb611 100644 --- a/accel-pptpd/triton/mempool.c +++ b/accel-pptpd/triton/mempool.c @@ -47,6 +47,10 @@ void *mempool_alloc(mempool_t *pool) } spin_unlock(&p->lock); it = malloc(sizeof(*it) + p->size); + if (!it) { + triton_log_error("out of memory\n"); + return NULL; + } it->owner = p; it->magic = p->magic; return it->ptr; diff --git a/accel-pptpd/triton/triton.c b/accel-pptpd/triton/triton.c index ba08c12..4ecf0a8 100644 --- a/accel-pptpd/triton/triton.c +++ b/accel-pptpd/triton/triton.c @@ -23,6 +23,7 @@ struct triton_context_t *default_ctx; static int terminate; static mempool_t *ctx_pool; +static mempool_t *call_pool; void triton_thread_wakeup(struct _triton_thread_t *thread) { @@ -74,6 +75,7 @@ static void ctx_thread(struct _triton_context_t *ctx) { struct _triton_md_handler_t *h; struct _triton_timer_t *t; + struct _triton_ctx_call_t *call; uint64_t tt; ucontext_t *uctx; @@ -110,6 +112,13 @@ static void ctx_thread(struct _triton_context_t *ctx) h->trig_epoll_events = 0; continue; } + if (!list_empty(&ctx->pending_calls)) { + call = list_entry(ctx->pending_calls.next, typeof(*call), entry); + list_del(&call->entry); + spin_unlock(&ctx->lock); + call->func(call->arg); + mempool_free(call); + } ctx->thread = NULL; spin_unlock(&ctx->lock); @@ -159,6 +168,9 @@ int __export triton_context_register(struct triton_context_t *ud) { struct _triton_context_t *ctx = mempool_alloc(ctx_pool); + if (!ctx) + return -1; + memset(ctx, 0, sizeof(*ctx)); ctx->ud = ud; spinlock_init(&ctx->lock); @@ -166,6 +178,7 @@ int __export triton_context_register(struct triton_context_t *ud) INIT_LIST_HEAD(&ctx->timers); INIT_LIST_HEAD(&ctx->pending_handlers); INIT_LIST_HEAD(&ctx->pending_timers); + INIT_LIST_HEAD(&ctx->pending_calls); if (getcontext(&ctx->uctx)) { triton_log_error("getcontext: %s\n", strerror(errno)); @@ -252,9 +265,28 @@ void __export triton_context_wakeup(struct triton_context_t *ud) triton_thread_wakeup(ctx->thread); } +int __export triton_context_call(struct triton_context_t *ud, void (*func)(void *), void *arg) +{ + struct _triton_context_t *ctx = (struct _triton_context_t *)ud->tpd; + struct _triton_ctx_call_t *call = mempool_alloc(call_pool); + + if (!call) + return -1; + + call->func = func; + call->arg = arg; + + spin_lock(&ctx->lock); + list_add_tail(&call->entry, &ctx->pending_calls); + spin_unlock(&ctx->lock); + + return 0; +} + int __export triton_init(const char *conf_file, const char *mod_sect) { ctx_pool = mempool_create(sizeof(struct _triton_context_t)); + call_pool = mempool_create(sizeof(struct _triton_ctx_call_t)); default_ctx = malloc(sizeof(*default_ctx)); if (!default_ctx) { diff --git a/accel-pptpd/triton/triton.h b/accel-pptpd/triton/triton.h index 735264a..d9baa7d 100644 --- a/accel-pptpd/triton/triton.h +++ b/accel-pptpd/triton/triton.h @@ -45,6 +45,7 @@ int triton_context_register(struct triton_context_t *); void triton_context_unregister(struct triton_context_t *); void triton_context_schedule(struct triton_context_t *); void triton_context_wakeup(struct triton_context_t *); +int triton_context_call(struct triton_context_t *, void (*func)(void *), void *arg); #define MD_MODE_READ 1 #define MD_MODE_WRITE 2 diff --git a/accel-pptpd/triton/triton_p.h b/accel-pptpd/triton/triton_p.h index 0aa37b1..5e498fc 100644 --- a/accel-pptpd/triton/triton_p.h +++ b/accel-pptpd/triton/triton_p.h @@ -33,6 +33,7 @@ struct _triton_context_t struct list_head timers; struct list_head pending_handlers; struct list_head pending_timers; + struct list_head pending_calls; ucontext_t uctx; @@ -71,6 +72,14 @@ struct _triton_event_t struct list_head handlers; }; +struct _triton_ctx_call_t +{ + struct list_head entry; + + void *arg; + void (*func)(void *); +}; + typedef void * mempool_t; mempool_t *mempool_create(int size); void *mempool_alloc(mempool_t*); |