diff --git a/src/auth.c b/src/auth.c index a24d0536..27f929e3 100644 --- a/src/auth.c +++ b/src/auth.c @@ -111,7 +111,7 @@ auth_client_action(char *ip, char *mac, t_authaction action) case AUTH_MAKE_AUTHENTICATED: if(client->fw_connection_state != FW_MARK_AUTHENTICATED) { client->fw_connection_state = FW_MARK_AUTHENTICATED; - iptables_fw_access(AUTH_MAKE_AUTHENTICATED,client->ip,client->mac); + iptables_fw_access(AUTH_MAKE_AUTHENTICATED, client); authenticated_since_start++; } else { debug(LOG_INFO, "Nothing to do, %s %s already authenticated", client->ip, client->mac); @@ -120,7 +120,7 @@ auth_client_action(char *ip, char *mac, t_authaction action) case AUTH_MAKE_DEAUTHENTICATED: if(client->fw_connection_state == FW_MARK_AUTHENTICATED) { - iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, client->ip, client->mac); + iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, client); } client_list_delete(client); break; diff --git a/src/client_list.c b/src/client_list.c index b367eb46..50316eb0 100644 --- a/src/client_list.c +++ b/src/client_list.c @@ -49,6 +49,7 @@ /** Client counter */ static int client_count = 0; +static t_client **client_arr; /** Time last client added */ static unsigned long int last_client_time = 0; @@ -83,8 +84,17 @@ client_get_first_client(void) void client_list_init(void) { + s_config *config; + int i; + firstclient = NULL; client_count = 0; + + config = config_get_config(); + client_arr = safe_malloc(config->maxclients * sizeof(t_client *)); + + for (i = 0; i < config->maxclients; i++) + client_arr[i] = NULL; } /** @internal @@ -103,7 +113,7 @@ _client_list_append(const char *ip, const char *mac, const char *token) { t_client *client, *prevclient; s_config *config; - int maxclients; + int maxclients, i; config = config_get_config(); maxclients = config->maxclients; @@ -133,6 +143,15 @@ _client_list_append(const char *ip, const char *mac, const char *token) client->counters.last_updated = last_client_time; client->added_time = last_client_time; + for (i = 0; i < maxclients; i++) { + if (client_arr[i]) + continue; + break; + } + + client_arr[i] = client; + client->idx = i; + debug(LOG_NOTICE, "Adding %s %s token %s to client list", client->ip, client->mac, client->token ? client->token : "none"); @@ -301,6 +320,9 @@ _client_list_free_node(t_client * client) if (client->token != NULL) free(client->token); + if (client_arr[client->idx] == client) + client_arr[client->idx] = NULL; + free(client); } diff --git a/src/client_list.h b/src/client_list.h index 407a4e29..2b8e24d6 100644 --- a/src/client_list.h +++ b/src/client_list.h @@ -50,6 +50,9 @@ typedef struct _t_client { t_counters counters; /**< @brief Counters for input/output of the client. */ int attempts; /**< @brief Number of authentication attempts */ + int download_limit; /**< @brief Download limit, kb/s */ + int upload_limit; /**< @brief Upload limit, kb/s */ + int idx; } t_client; /** @brief Get the first element of the list of connected clients diff --git a/src/conf.c b/src/conf.c index 4dd66b78..704f663b 100644 --- a/src/conf.c +++ b/src/conf.c @@ -75,6 +75,9 @@ typedef enum { oGatewayAddress, oGatewayPort, oRemoteAuthenticatorAction, + oEnablePreAuth, + oEnableVoucher, + oForceVoucher, oPasswordAuthentication, oUsernameAuthentication, oPasswordAttempts, @@ -131,6 +134,9 @@ static const struct { { "gatewayaddress", oGatewayAddress }, { "gatewayport", oGatewayPort }, { "remoteauthenticatoraction", oRemoteAuthenticatorAction }, + { "enablepreauth", oEnablePreAuth }, + { "enablevoucher", oEnableVoucher }, + { "forcevoucher", oForceVoucher }, { "passwordauthentication", oPasswordAuthentication }, { "usernameauthentication", oUsernameAuthentication }, { "passwordattempts", oPasswordAttempts }, @@ -743,6 +749,21 @@ config_read(const char *filename) case oRemoteAuthenticatorAction: config.remote_auth_action = safe_strdup(p1); break; + case oEnablePreAuth: + value = parse_boolean_value(p1); + if (value != - 1) + config.enable_preauth = value; + break; + case oEnableVoucher: + value = parse_boolean_value(p1); + if (value != - 1) + config.enable_voucher = value; + break; + case oForceVoucher: + value = parse_boolean_value(p1); + if (value != - 1) + config.force_voucher = value; + break; case oFirewallRuleSet: parse_firewall_ruleset(p1, fd, filename, &linenum); break; diff --git a/src/conf.h b/src/conf.h index 93881e7a..25f337bb 100644 --- a/src/conf.h +++ b/src/conf.h @@ -144,6 +144,9 @@ typedef struct { char *gw_address; /**< @brief Internal IP address for our web server */ unsigned int gw_port; /**< @brief Port the webserver will run on */ char *remote_auth_action; /**< @brief Path for remote auth */ + char enable_preauth; /**< @brief enable pre-authentication support */ + char enable_voucher; /**< @brief enable voucher support */ + char force_voucher; /**< @brief force voucher */ char *webroot; /**< @brief Directory containing splash pages, etc. */ char *splashpage; /**< @brief Name of main splash page */ char *infoskelpage; /**< @brief Name of info skeleton page */ diff --git a/src/firewall.c b/src/firewall.c index 28d1ecc2..41003f7b 100644 --- a/src/firewall.c +++ b/src/firewall.c @@ -67,10 +67,10 @@ #include "safe.h" #include "debug.h" #include "conf.h" +#include "client_list.h" #include "firewall.h" #include "fw_iptables.h" #include "auth.h" -#include "client_list.h" extern pthread_mutex_t client_list_mutex; @@ -215,7 +215,7 @@ fw_refresh_client_list(void) cp1->ip, cp1->mac, config->checkinterval * config->clienttimeout, cp1->counters.incoming/1000, cp1->counters.outgoing/1000); if(cp1->fw_connection_state == FW_MARK_AUTHENTICATED) { - iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, cp1->ip, cp1->mac); + iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, cp1); } client_list_delete(cp1); } else if (added_time + (config->checkinterval * config->clientforceout) <= now) { @@ -224,7 +224,7 @@ fw_refresh_client_list(void) cp1->ip, cp1->mac, config->checkinterval * config->clientforceout, cp1->counters.incoming/1000, cp1->counters.outgoing/1000); if(cp1->fw_connection_state == FW_MARK_AUTHENTICATED) { - iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, cp1->ip, cp1->mac); + iptables_fw_access(AUTH_MAKE_DEAUTHENTICATED, cp1); } client_list_delete(cp1); } diff --git a/src/fw_iptables.c b/src/fw_iptables.c index e4151a11..83f55f24 100644 --- a/src/fw_iptables.c +++ b/src/fw_iptables.c @@ -44,11 +44,11 @@ #include "safe.h" #include "conf.h" #include "auth.h" +#include "client_list.h" #include "fw_iptables.h" #include "firewall.h" #include "debug.h" #include "util.h" -#include "client_list.h" #include "tc.h" static char * _iptables_compile(const char *, char *, t_firewall_rule *); @@ -410,7 +410,7 @@ iptables_fw_init(void) */ /* packets coming in on gw_interface jump to CHAIN_OUTGOING */ - rc |= iptables_do_command("-t nat -I PREROUTING -i %s -s %s -j " CHAIN_OUTGOING, gw_interface, gw_iprange); + rc |= iptables_do_command("-t nat -A PREROUTING -i %s -s %s -j " CHAIN_OUTGOING, gw_interface, gw_iprange); /* CHAIN_OUTGOING, packets marked TRUSTED ACCEPT */ rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -m mark --mark 0x%x%s -j ACCEPT", FW_MARK_TRUSTED, markmask); /* CHAIN_OUTGOING, packets marked AUTHENTICATED ACCEPT */ @@ -501,7 +501,7 @@ iptables_fw_init(void) */ /* packets coming in on gw_interface jump to CHAIN_TO_INTERNET */ - rc |= iptables_do_command("-t filter -I FORWARD -i %s -s %s -j " CHAIN_TO_INTERNET, gw_interface, gw_iprange); + rc |= iptables_do_command("-t filter -A FORWARD -i %s -s %s -j " CHAIN_TO_INTERNET, gw_interface, gw_iprange); /* CHAIN_TO_INTERNET packets marked BLOCKED DROP */ rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j DROP", FW_MARK_BLOCKED, markmask); /* CHAIN_TO_INTERNET, invalid packets DROP */ @@ -716,31 +716,49 @@ iptables_fw_destroy_mention( /** Insert or delete firewall mangle rules marking a client's packets. */ int -iptables_fw_access(t_authaction action, const char *ip, const char *mac) -{ - int rc; +iptables_fw_access(t_authaction action, t_client *client) { + int rc = 0, download_limit, upload_limit; + s_config *config; + char *download_imqname, *upload_imqname; fw_quiet = 0; + config = config_get_config(); + safe_asprintf(&download_imqname,"imq%d",config->download_imq); /* must free */ + safe_asprintf(&upload_imqname,"imq%d",config->upload_imq); /* must free */ + + download_limit = config->download_limit; + upload_limit = config->upload_limit; + + if ((client->download_limit > 0) && (client->upload_limit > 0)) { + download_limit = client->download_limit; + upload_limit = client->upload_limit; + } + switch(action) { case AUTH_MAKE_AUTHENTICATED: - debug(LOG_NOTICE, "Authenticating %s %s", ip, mac); + debug(LOG_NOTICE, "Authenticating %s %s", client->ip, client->mac); /* This rule is for marking upload (outgoing) packets, and for upload byte counting */ - rc = iptables_do_command("-t mangle -A " CHAIN_OUTGOING " -s %s -m mac --mac-source %s -j MARK %s 0x%x", ip, mac, markop, FW_MARK_AUTHENTICATED); + rc |= iptables_do_command("-t mangle -I " CHAIN_OUTGOING " -s %s -m mac --mac-source %s -j MARK %s 0x%x%x", client->ip, client->mac, markop, client->idx + 10, FW_MARK_AUTHENTICATED); + rc |= iptables_do_command("-t mangle -I " CHAIN_INCOMING " -d %s -j MARK %s 0x%x%x", client->ip, markop, client->idx + 10, FW_MARK_AUTHENTICATED); /* This rule is just for download (incoming) byte counting, see iptables_fw_counters_update() */ - rc = iptables_do_command("-t mangle -A " CHAIN_INCOMING " -d %s -j ACCEPT", ip); + rc |= iptables_do_command("-t mangle -A " CHAIN_INCOMING " -d %s -j ACCEPT", client->ip); + rc |= tc_attach_client(download_imqname, download_limit, upload_imqname, upload_limit, client->idx, FW_MARK_AUTHENTICATED); break; case AUTH_MAKE_DEAUTHENTICATED: /* Remove the authentication rules. */ - debug(LOG_NOTICE, "Deauthenticating %s %s", ip, mac); - rc = iptables_do_command("-t mangle -D " CHAIN_OUTGOING " -s %s -m mac --mac-source %s -j MARK %s 0x%x", ip, mac, markop, FW_MARK_AUTHENTICATED); - rc = iptables_do_command("-t mangle -D " CHAIN_INCOMING " -d %s -j ACCEPT", ip); + debug(LOG_NOTICE, "Deauthenticating %s %s", client->ip, client->mac); + rc |= iptables_do_command("-t mangle -D " CHAIN_OUTGOING " -s %s -m mac --mac-source %s -j MARK %s 0x%x%x", client->ip, client->mac, markop, client->idx + 10, FW_MARK_AUTHENTICATED); + rc |= iptables_do_command("-t mangle -D " CHAIN_INCOMING " -d %s -j ACCEPT", client->ip); + rc |= tc_detach_client(download_imqname, upload_imqname, client->idx); break; default: rc = -1; break; } + free(upload_imqname); + free(download_imqname); return rc; } diff --git a/src/fw_iptables.h b/src/fw_iptables.h index 72cfc8fe..074d5a61 100644 --- a/src/fw_iptables.h +++ b/src/fw_iptables.h @@ -55,7 +55,7 @@ int iptables_fw_destroy(void); int iptables_fw_destroy_mention( const char * table, const char * chain, const char * mention); /** @brief Define the access of a specific client */ -int iptables_fw_access(t_authaction action, const char *ip, const char *mac); +int iptables_fw_access(t_authaction action, t_client *client); /** @brief Return the total download usage in bytes */ unsigned long long int iptables_fw_total_download(); diff --git a/src/http.c b/src/http.c index 27d20a58..8f280c80 100644 --- a/src/http.c +++ b/src/http.c @@ -51,6 +51,76 @@ extern pthread_mutex_t client_list_mutex; +static int data_extract_bw(char *buff, t_client *client) +{ + char *download_ptr, *upload_ptr; + int download, upload; + + download_ptr = strchr(buff, ' '); + if (!download_ptr) + goto err; + + *download_ptr = '\0'; + download_ptr++; + + upload_ptr = strchr(download_ptr, ' '); + if (!upload_ptr) + goto err; + + *upload_ptr = '\0'; + upload_ptr++; + + download = strtol(download_ptr, NULL, 10); + if (download < 1) + goto err; + + upload = strtol(upload_ptr, NULL, 10); + if (upload < 1) + goto err; + + client->download_limit = download; + client->upload_limit = upload; + return 0; + +err: + client->download_limit = 0; + client->upload_limit = 0; + return -1; +} + +char *system_exec(char *cmd) +{ + char *data = NULL; + int error, pipes[2], stderr_fd = -1; + int data_len = 100, read_len; + + data = malloc(data_len); + if (!data) + goto out; + + memset(data, 0, data_len); + + error = pipe(pipes); + if (error < 0) + goto out; + + stderr_fd = dup(STDOUT_FILENO); + + dup2(pipes[1], STDOUT_FILENO); + close(pipes[1]); + + error = system(cmd); + + dup2(stderr_fd, STDOUT_FILENO); + close(stderr_fd); + + read_len = read(pipes[0], data, data_len - 1); + data[read_len] = '\0'; + + close(pipes[0]); +out: + return data; +} /* response handler for HTTP 405 Method Not Allowed */ void @@ -110,7 +180,8 @@ http_nodogsplash_first_contact(request *r) t_client *client; t_auth_target *authtarget; s_config *config; - char *redir; + char *redir, cmd_buff[50], *data = NULL; + int ret, seconds; /* only allow GET requests */ if (r->request.method != HTTP_GET) { @@ -132,9 +203,31 @@ http_nodogsplash_first_contact(request *r) if(config->authenticate_immediately) { /* Don't serve splash, just authenticate */ http_nodogsplash_callback_action(r,authtarget,AUTH_MAKE_AUTHENTICATED); + } else if (config->enable_preauth) { + snprintf(cmd_buff, sizeof(cmd_buff) - 1, "captive_portal auth_status %s", client->mac); + data = system_exec(cmd_buff); + + if(!data) + goto serve_splash; + + seconds = strtol(data, NULL, 10); + if(seconds < 1) + goto serve_splash; + + ret = data_extract_bw(data, client); + if(ret < 0) + goto serve_splash; + + debug(LOG_NOTICE, "Remote auth data: client [%s, %s] authenticated %d seconds", + client->mac, client->ip, seconds); + http_nodogsplash_callback_action(r,authtarget,AUTH_MAKE_AUTHENTICATED); + client->added_time = time(NULL) - (config->checkinterval * config->clientforceout) + seconds; + free(data); } else { /* Serve the splash page (or redirect to remote authenticator) */ - http_nodogsplash_serve_splash(r,authtarget); +serve_splash: + free(data); + http_nodogsplash_serve_splash(r,authtarget, NULL); } http_nodogsplash_free_authtarget(authtarget); @@ -248,16 +341,64 @@ http_nodogsplash_callback_action(request *r, void http_nodogsplash_callback_auth(httpd *webserver, request *r) { + s_config *config; + t_client *client; t_auth_target *authtarget; + char *ip, *mac, *msg = NULL, cmd_buff[50], *data = NULL; + int ret, seconds; /* Get info we need from request, and do action */ authtarget = http_nodogsplash_decode_authtarget(r); + config = config_get_config(); + + if (config->enable_voucher && ((authtarget->voucher) || (config->force_voucher))) { + ip = r->clientAddr; + mac = arp_get(ip); + + if (!mac) + goto serve_splash; - if(http_nodogsplash_check_userpass(r,authtarget)) { + LOCK_CLIENT_LIST(); + client = client_list_find(ip, mac); + UNLOCK_CLIENT_LIST(); + + if (!client) + goto serve_splash; + + snprintf(cmd_buff, sizeof(cmd_buff) - 1, "captive_portal auth_voucher %s %s", + client->mac, authtarget->voucher); + data = system_exec(cmd_buff); + + if (!data) + goto serve_splash; + + seconds = strtol(data, NULL, 10); + if (seconds < 1) + goto serve_splash; + + ret = data_extract_bw(data, client); + if (ret < 0) + goto serve_splash; + + debug(LOG_NOTICE, "Remote voucher: client [%s, %s] authenticated %d seconds", + client->mac, client->ip, seconds); + free(mac); + free(data); + http_nodogsplash_callback_action(r,authtarget,AUTH_MAKE_AUTHENTICATED); + client->added_time = time(NULL) - (config->checkinterval * config->clientforceout) + seconds; + } else if(http_nodogsplash_check_userpass(r,authtarget)) { http_nodogsplash_callback_action (r,authtarget,AUTH_MAKE_AUTHENTICATED); } else { /* Password check failed; just serve them the splash page again */ - http_nodogsplash_serve_splash(r,authtarget); +serve_splash: + if (data) { + msg = strchr(data, ' '); + if (msg) + msg++; + } + http_nodogsplash_serve_splash(r,authtarget,msg); + free(mac); + free(data); } http_nodogsplash_free_authtarget(authtarget); @@ -324,7 +465,7 @@ http_nodogsplash_redirect_remote_auth(request *r, t_auth_target *authtarget) * or redirect to remote authenticator as required. */ void -http_nodogsplash_serve_splash(request *r, t_auth_target *authtarget) +http_nodogsplash_serve_splash(request *r, t_auth_target *authtarget, char *error_msg) { char *tmpstr; char line [MAX_BUF]; @@ -341,6 +482,10 @@ http_nodogsplash_serve_splash(request *r, t_auth_target *authtarget) } /* Set variables; these can be interpolated in the splash page text. */ + if (error_msg) + httpdAddVariable(r,"error_msg", error_msg); + else + httpdAddVariable(r,"error_msg", ""); httpdAddVariable(r,"gatewayname",config->gw_name); httpdAddVariable(r,"tok",authtarget->token); httpdAddVariable(r,"redir",authtarget->redir); @@ -487,6 +632,10 @@ http_nodogsplash_decode_authtarget(request *r) authtarget->info = safe_strdup(var->value); } + var = httpdGetVariableByName(r,"voucher"); + if(var && var->value) + authtarget->voucher = var->value; + return authtarget; } diff --git a/src/http.h b/src/http.h index 74394756..2649736a 100644 --- a/src/http.h +++ b/src/http.h @@ -46,6 +46,7 @@ typedef struct _auth_target_t { char *authtarget; /**< @brief Deny action */ char *token; /**< @brief Client token */ char *redir; /**< @brief Client redirect target */ + char *voucher; /**< @brief voucher token */ char *username; /**< @brief User name */ char *password; /**< @brief User password */ char *info; /**< @brief Auxilliary info */ @@ -68,7 +69,7 @@ void http_nodogsplash_redirect(request *r, char *url); /**@brief Redirect to remote auth server */ void http_nodogsplash_redirect_remote_auth(request *r, t_auth_target *authtarget); /**@brief Serve the splash page from its file */ -void http_nodogsplash_serve_splash(request *r, t_auth_target *authtarget); +void http_nodogsplash_serve_splash(request *r, t_auth_target *authtarget, char *error_msg); /**@brief Serve the info page from its file */ void http_nodogsplash_serve_info(request *r, char *title, char *content); /**@brief Handle initial contact from client */ diff --git a/src/ndsctl_thread.c b/src/ndsctl_thread.c index 2eb2cec5..5f389bd1 100644 --- a/src/ndsctl_thread.c +++ b/src/ndsctl_thread.c @@ -47,9 +47,10 @@ #include "debug.h" #include "auth.h" #include "safe.h" +#include "client_list.h" #include "fw_iptables.h" #include "firewall.h" -#include "client_list.h" + #include "ndsctl_thread.h" /* Defined in clientlist.c */ diff --git a/src/tc.c b/src/tc.c index 5acf1c6c..78d2e886 100644 --- a/src/tc.c +++ b/src/tc.c @@ -35,12 +35,13 @@ #include "safe.h" #include "conf.h" +#include "client_list.h" #include "auth.h" #include "fw_iptables.h" #include "firewall.h" #include "debug.h" #include "util.h" -#include "client_list.h" + #include "tc.h" @@ -76,6 +77,46 @@ tc_do_command(char *format, ...) return rc; } +int +tc_attach_client(char *down_dev, int download_limit, char *up_dev, int upload_limit, int idx, int fw_mark) { + int burst; + int mtu = MTU + 40; + int rc = 0; + int r2q = 10; + + if(download_limit < 120) r2q = 1; + + burst = download_limit * 1000 / 8 / HZ; /* burst (buffer size) in bytes */ + burst = burst < mtu ? mtu : burst; /* but burst should be at least mtu */ + + rc |= tc_do_command("class add dev %s parent 1:1 classid 1:%i htb rate %dkbit ceil %dkbit burst %d cburst %d mtu %d prio 1", + down_dev, idx + 10, download_limit, download_limit, burst*10, burst, mtu); + rc |= tc_do_command("filter add dev %s protocol ip parent 1: handle 0x%x%x fw flowid 1:%i", + down_dev, idx + 10, fw_mark, idx + 10); + + /* to avoid some kernel warnings with small rates */ + if(upload_limit < 120) r2q = 1; + + burst = upload_limit * 1000 / 8 / HZ; /* burst (buffer size) in bytes */ + burst = burst < mtu ? mtu : burst; /* but burst should be at least mtu */ + + rc |= tc_do_command("class add dev %s parent 1:1 classid 1:%i htb rate %dkbit ceil %dkbit burst %d cburst %d mtu %d prio 1", + up_dev, idx + 10, upload_limit, upload_limit, burst*10, burst, mtu); + rc |= tc_do_command("filter add dev %s protocol ip parent 1: handle 0x%x%x fw flowid 1:%i", + up_dev, idx + 10, fw_mark, idx + 10); + return rc; + +} + +int +tc_detach_client(char *down_dev, char *up_dev, int idx) { + int rc = 0; + + rc |= tc_do_command("class del dev %s parent 1: classid 1:%i", down_dev, idx + 10); + rc |= tc_do_command("class del dev %s parent 1: classid 1:%i", up_dev, idx + 10); + + return rc; +} /* Use HTB as a upload qdisc. * dev is name of device to attach qdisc to (typically an IMQ) @@ -86,20 +127,18 @@ tc_do_command(char *format, ...) static int tc_attach_upload_qdisc(char *dev, int upload_limit) { + int rc = 0; int burst; int mtu = MTU + 40; - int rc = 0; - int r2q = 10; - - /* to avoid some kernel warnings with small rates */ - if(upload_limit < 120) r2q = 1; burst = upload_limit * 1000 / 8 / HZ; /* burst (buffer size) in bytes */ burst = burst < mtu ? mtu : burst; /* but burst should be at least mtu */ - rc |= tc_do_command("qdisc add dev %s root handle 1: htb default 1 r2q %d", dev,r2q); - rc |= tc_do_command("class add dev %s parent 1: classid 1:1 htb rate %dkbit ceil %dkbit burst %d cburst %d mtu %d prio 1", - dev, upload_limit, upload_limit, burst*2, burst, mtu); + rc |= tc_do_command("qdisc add dev %s root handle 1: htb default 2 r2q %d", dev, 1700); + rc |= tc_do_command("class add dev %s parent 1: classid 1:1 htb rate 100Mbps ceil 100Mbps burst %d cburst %d mtu %d", + dev, burst*10, burst, mtu); + rc |= tc_do_command("class add dev %s parent 1:1 classid 1:2 htb rate %dkbit ceil %dkbit burst %d cburst %d mtu %d prio 1", + dev, upload_limit, upload_limit, burst*10, burst, mtu); return rc; } @@ -113,21 +152,19 @@ tc_attach_upload_qdisc(char *dev, int upload_limit) static int tc_attach_download_qdisc(char *dev, int download_limit) { + int rc = 0; int burst; int mtu = MTU + 40; - int rc = 0; - int r2q = 10; - - /* to avoid some kernel warnings with small rates */ - if(download_limit < 120) r2q = 1; burst = download_limit * 1000 / 8 / HZ; /* burst (buffer size) in bytes */ burst = burst < mtu ? mtu : burst; /* but burst should be at least mtu */ + rc |= tc_do_command("qdisc add dev %s root handle 1: htb default 2 r2q %d", dev, 1700); + rc |= tc_do_command("class add dev %s parent 1: classid 1:1 htb rate 100Mbps ceil 100Mbps burst %d cburst %d mtu %d", + dev, burst*10, burst, mtu); + rc |= tc_do_command("class add dev %s parent 1:1 classid 1:2 htb rate %dkbit ceil %dkbit burst %d cburst %d mtu %d prio 1", + dev, download_limit, download_limit, burst*10, burst, mtu); - rc |= tc_do_command("qdisc add dev %s root handle 1: htb default 1 r2q %d", dev, r2q); - rc |= tc_do_command("class add dev %s parent 1: classid 1:1 htb rate %dkbit ceil %dkbit burst %d cburst %d mtu %d prio 1", - dev, download_limit, download_limit, burst*2, burst, mtu); return rc; }