/* * Copyright (c) 2019 AVM GmbH . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include static HANDLE_POOL_DECLARE(lan_shared, PCE_TABLE_LAN_SIZE); static HANDLE_POOL_DECLARE(dynamic, (PCE_RULE_IDX_DYNAMIC_LAST + 1) - PCE_RULE_IDX_DYNAMIC); static HANDLE_POOL_DECLARE(fixed, PCE_RULE_IDX_LAST - PCE_RULE_IDX_DYNAMIC_LAST); /* TODO Das muss irgendwie eleganter. */ static unsigned long *range_to_pool(enum pce_idx_range range) { switch (range) { case PCE_RANGE_LAN_SHARED: return lan_shared; case PCE_RANGE_DYNAMIC: return dynamic; case PCE_RANGE_FIXED: return fixed; default: return NULL; } } static unsigned long range_to_pool_size(enum pce_idx_range range) { switch (range) { case PCE_RANGE_LAN_SHARED: return PCE_TABLE_LAN_SIZE; case PCE_RANGE_DYNAMIC: return (PCE_RULE_IDX_DYNAMIC_LAST + 1) - PCE_RULE_IDX_DYNAMIC; case PCE_RANGE_FIXED: return PCE_RULE_IDX_LAST - PCE_RULE_IDX_DYNAMIC_LAST; default: return 0ul; } } static int pool_to_offset(unsigned long *pool) { if (pool == fixed) return PCE_RULE_IDX_FIXED; if (pool == dynamic) return PCE_RULE_IDX_DYNAMIC; if (pool == lan_shared) return PCE_RULE_IDX_LAN_SHARED; return -1; } static unsigned long *idx_to_pool(int idx) { if (idx > PCE_RULE_IDX_LAST) return NULL; else if (idx > PCE_RULE_IDX_DYNAMIC_LAST) return fixed; else if (idx > PCE_RULE_IDX_LAN_SHARED_LAST) return dynamic; else if (idx >= PCE_RULE_IDX_LAN_SHARED) return lan_shared; else return NULL; } int pce_idx_alloc(enum pce_idx_range range) { int pool_idx; unsigned long *pool, size; pool = range_to_pool(range); if (!pool || pool == fixed) return -1; size = range_to_pool_size(range); pool_idx = handle_alloc(pool, size); if (pool_idx >= size) return -2; return pool_idx + pool_to_offset(pool); } EXPORT_SYMBOL(pce_idx_alloc); bool pce_idx_request(int idx) { unsigned long *pool; int pool_idx; pool = idx_to_pool(idx); pool_idx = idx - pool_to_offset(pool); pr_debug("%s %pK: %d\n", __func__, pool, pool_idx); return (pool_idx >= 0 && handle_request(pool_idx, pool)); } EXPORT_SYMBOL(pce_idx_request); void pce_idx_free(int idx) { unsigned long *pool; int pool_idx; pool = idx_to_pool(idx); pool_idx = idx - pool_to_offset(pool); handle_free(pool_idx, pool); } EXPORT_SYMBOL(pce_idx_free);