cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

calipso.c (38684B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * CALIPSO - Common Architecture Label IPv6 Security Option
      4 *
      5 * This is an implementation of the CALIPSO protocol as specified in
      6 * RFC 5570.
      7 *
      8 * Authors: Paul Moore <paul.moore@hp.com>
      9 *          Huw Davies <huw@codeweavers.com>
     10 */
     11
     12/* (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
     13 * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
     14 */
     15
     16#include <linux/init.h>
     17#include <linux/types.h>
     18#include <linux/rcupdate.h>
     19#include <linux/list.h>
     20#include <linux/spinlock.h>
     21#include <linux/string.h>
     22#include <linux/jhash.h>
     23#include <linux/audit.h>
     24#include <linux/slab.h>
     25#include <net/ip.h>
     26#include <net/icmp.h>
     27#include <net/tcp.h>
     28#include <net/netlabel.h>
     29#include <net/calipso.h>
     30#include <linux/atomic.h>
     31#include <linux/bug.h>
     32#include <asm/unaligned.h>
     33#include <linux/crc-ccitt.h>
     34
     35/* Maximium size of the calipso option including
     36 * the two-byte TLV header.
     37 */
     38#define CALIPSO_OPT_LEN_MAX (2 + 252)
     39
     40/* Size of the minimum calipso option including
     41 * the two-byte TLV header.
     42 */
     43#define CALIPSO_HDR_LEN (2 + 8)
     44
     45/* Maximium size of the calipso option including
     46 * the two-byte TLV header and upto 3 bytes of
     47 * leading pad and 7 bytes of trailing pad.
     48 */
     49#define CALIPSO_OPT_LEN_MAX_WITH_PAD (3 + CALIPSO_OPT_LEN_MAX + 7)
     50
     51 /* Maximium size of u32 aligned buffer required to hold calipso
     52  * option.  Max of 3 initial pad bytes starting from buffer + 3.
     53  * i.e. the worst case is when the previous tlv finishes on 4n + 3.
     54  */
     55#define CALIPSO_MAX_BUFFER (6 + CALIPSO_OPT_LEN_MAX)
     56
     57/* List of available DOI definitions */
     58static DEFINE_SPINLOCK(calipso_doi_list_lock);
     59static LIST_HEAD(calipso_doi_list);
     60
     61/* Label mapping cache */
     62int calipso_cache_enabled = 1;
     63int calipso_cache_bucketsize = 10;
     64#define CALIPSO_CACHE_BUCKETBITS     7
     65#define CALIPSO_CACHE_BUCKETS        BIT(CALIPSO_CACHE_BUCKETBITS)
     66#define CALIPSO_CACHE_REORDERLIMIT   10
     67struct calipso_map_cache_bkt {
     68	spinlock_t lock;
     69	u32 size;
     70	struct list_head list;
     71};
     72
     73struct calipso_map_cache_entry {
     74	u32 hash;
     75	unsigned char *key;
     76	size_t key_len;
     77
     78	struct netlbl_lsm_cache *lsm_data;
     79
     80	u32 activity;
     81	struct list_head list;
     82};
     83
     84static struct calipso_map_cache_bkt *calipso_cache;
     85
     86static void calipso_cache_invalidate(void);
     87static void calipso_doi_putdef(struct calipso_doi *doi_def);
     88
     89/* Label Mapping Cache Functions
     90 */
     91
     92/**
     93 * calipso_cache_entry_free - Frees a cache entry
     94 * @entry: the entry to free
     95 *
     96 * Description:
     97 * This function frees the memory associated with a cache entry including the
     98 * LSM cache data if there are no longer any users, i.e. reference count == 0.
     99 *
    100 */
    101static void calipso_cache_entry_free(struct calipso_map_cache_entry *entry)
    102{
    103	if (entry->lsm_data)
    104		netlbl_secattr_cache_free(entry->lsm_data);
    105	kfree(entry->key);
    106	kfree(entry);
    107}
    108
    109/**
    110 * calipso_map_cache_hash - Hashing function for the CALIPSO cache
    111 * @key: the hash key
    112 * @key_len: the length of the key in bytes
    113 *
    114 * Description:
    115 * The CALIPSO tag hashing function.  Returns a 32-bit hash value.
    116 *
    117 */
    118static u32 calipso_map_cache_hash(const unsigned char *key, u32 key_len)
    119{
    120	return jhash(key, key_len, 0);
    121}
    122
    123/**
    124 * calipso_cache_init - Initialize the CALIPSO cache
    125 *
    126 * Description:
    127 * Initializes the CALIPSO label mapping cache, this function should be called
    128 * before any of the other functions defined in this file.  Returns zero on
    129 * success, negative values on error.
    130 *
    131 */
    132static int __init calipso_cache_init(void)
    133{
    134	u32 iter;
    135
    136	calipso_cache = kcalloc(CALIPSO_CACHE_BUCKETS,
    137				sizeof(struct calipso_map_cache_bkt),
    138				GFP_KERNEL);
    139	if (!calipso_cache)
    140		return -ENOMEM;
    141
    142	for (iter = 0; iter < CALIPSO_CACHE_BUCKETS; iter++) {
    143		spin_lock_init(&calipso_cache[iter].lock);
    144		calipso_cache[iter].size = 0;
    145		INIT_LIST_HEAD(&calipso_cache[iter].list);
    146	}
    147
    148	return 0;
    149}
    150
    151/**
    152 * calipso_cache_invalidate - Invalidates the current CALIPSO cache
    153 *
    154 * Description:
    155 * Invalidates and frees any entries in the CALIPSO cache.  Returns zero on
    156 * success and negative values on failure.
    157 *
    158 */
    159static void calipso_cache_invalidate(void)
    160{
    161	struct calipso_map_cache_entry *entry, *tmp_entry;
    162	u32 iter;
    163
    164	for (iter = 0; iter < CALIPSO_CACHE_BUCKETS; iter++) {
    165		spin_lock_bh(&calipso_cache[iter].lock);
    166		list_for_each_entry_safe(entry,
    167					 tmp_entry,
    168					 &calipso_cache[iter].list, list) {
    169			list_del(&entry->list);
    170			calipso_cache_entry_free(entry);
    171		}
    172		calipso_cache[iter].size = 0;
    173		spin_unlock_bh(&calipso_cache[iter].lock);
    174	}
    175}
    176
    177/**
    178 * calipso_cache_check - Check the CALIPSO cache for a label mapping
    179 * @key: the buffer to check
    180 * @key_len: buffer length in bytes
    181 * @secattr: the security attribute struct to use
    182 *
    183 * Description:
    184 * This function checks the cache to see if a label mapping already exists for
    185 * the given key.  If there is a match then the cache is adjusted and the
    186 * @secattr struct is populated with the correct LSM security attributes.  The
    187 * cache is adjusted in the following manner if the entry is not already the
    188 * first in the cache bucket:
    189 *
    190 *  1. The cache entry's activity counter is incremented
    191 *  2. The previous (higher ranking) entry's activity counter is decremented
    192 *  3. If the difference between the two activity counters is geater than
    193 *     CALIPSO_CACHE_REORDERLIMIT the two entries are swapped
    194 *
    195 * Returns zero on success, -ENOENT for a cache miss, and other negative values
    196 * on error.
    197 *
    198 */
    199static int calipso_cache_check(const unsigned char *key,
    200			       u32 key_len,
    201			       struct netlbl_lsm_secattr *secattr)
    202{
    203	u32 bkt;
    204	struct calipso_map_cache_entry *entry;
    205	struct calipso_map_cache_entry *prev_entry = NULL;
    206	u32 hash;
    207
    208	if (!calipso_cache_enabled)
    209		return -ENOENT;
    210
    211	hash = calipso_map_cache_hash(key, key_len);
    212	bkt = hash & (CALIPSO_CACHE_BUCKETS - 1);
    213	spin_lock_bh(&calipso_cache[bkt].lock);
    214	list_for_each_entry(entry, &calipso_cache[bkt].list, list) {
    215		if (entry->hash == hash &&
    216		    entry->key_len == key_len &&
    217		    memcmp(entry->key, key, key_len) == 0) {
    218			entry->activity += 1;
    219			refcount_inc(&entry->lsm_data->refcount);
    220			secattr->cache = entry->lsm_data;
    221			secattr->flags |= NETLBL_SECATTR_CACHE;
    222			secattr->type = NETLBL_NLTYPE_CALIPSO;
    223			if (!prev_entry) {
    224				spin_unlock_bh(&calipso_cache[bkt].lock);
    225				return 0;
    226			}
    227
    228			if (prev_entry->activity > 0)
    229				prev_entry->activity -= 1;
    230			if (entry->activity > prev_entry->activity &&
    231			    entry->activity - prev_entry->activity >
    232			    CALIPSO_CACHE_REORDERLIMIT) {
    233				__list_del(entry->list.prev, entry->list.next);
    234				__list_add(&entry->list,
    235					   prev_entry->list.prev,
    236					   &prev_entry->list);
    237			}
    238
    239			spin_unlock_bh(&calipso_cache[bkt].lock);
    240			return 0;
    241		}
    242		prev_entry = entry;
    243	}
    244	spin_unlock_bh(&calipso_cache[bkt].lock);
    245
    246	return -ENOENT;
    247}
    248
    249/**
    250 * calipso_cache_add - Add an entry to the CALIPSO cache
    251 * @calipso_ptr: the CALIPSO option
    252 * @secattr: the packet's security attributes
    253 *
    254 * Description:
    255 * Add a new entry into the CALIPSO label mapping cache.  Add the new entry to
    256 * head of the cache bucket's list, if the cache bucket is out of room remove
    257 * the last entry in the list first.  It is important to note that there is
    258 * currently no checking for duplicate keys.  Returns zero on success,
    259 * negative values on failure.  The key stored starts at calipso_ptr + 2,
    260 * i.e. the type and length bytes are not stored, this corresponds to
    261 * calipso_ptr[1] bytes of data.
    262 *
    263 */
    264static int calipso_cache_add(const unsigned char *calipso_ptr,
    265			     const struct netlbl_lsm_secattr *secattr)
    266{
    267	int ret_val = -EPERM;
    268	u32 bkt;
    269	struct calipso_map_cache_entry *entry = NULL;
    270	struct calipso_map_cache_entry *old_entry = NULL;
    271	u32 calipso_ptr_len;
    272
    273	if (!calipso_cache_enabled || calipso_cache_bucketsize <= 0)
    274		return 0;
    275
    276	calipso_ptr_len = calipso_ptr[1];
    277
    278	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
    279	if (!entry)
    280		return -ENOMEM;
    281	entry->key = kmemdup(calipso_ptr + 2, calipso_ptr_len, GFP_ATOMIC);
    282	if (!entry->key) {
    283		ret_val = -ENOMEM;
    284		goto cache_add_failure;
    285	}
    286	entry->key_len = calipso_ptr_len;
    287	entry->hash = calipso_map_cache_hash(calipso_ptr, calipso_ptr_len);
    288	refcount_inc(&secattr->cache->refcount);
    289	entry->lsm_data = secattr->cache;
    290
    291	bkt = entry->hash & (CALIPSO_CACHE_BUCKETS - 1);
    292	spin_lock_bh(&calipso_cache[bkt].lock);
    293	if (calipso_cache[bkt].size < calipso_cache_bucketsize) {
    294		list_add(&entry->list, &calipso_cache[bkt].list);
    295		calipso_cache[bkt].size += 1;
    296	} else {
    297		old_entry = list_entry(calipso_cache[bkt].list.prev,
    298				       struct calipso_map_cache_entry, list);
    299		list_del(&old_entry->list);
    300		list_add(&entry->list, &calipso_cache[bkt].list);
    301		calipso_cache_entry_free(old_entry);
    302	}
    303	spin_unlock_bh(&calipso_cache[bkt].lock);
    304
    305	return 0;
    306
    307cache_add_failure:
    308	if (entry)
    309		calipso_cache_entry_free(entry);
    310	return ret_val;
    311}
    312
    313/* DOI List Functions
    314 */
    315
    316/**
    317 * calipso_doi_search - Searches for a DOI definition
    318 * @doi: the DOI to search for
    319 *
    320 * Description:
    321 * Search the DOI definition list for a DOI definition with a DOI value that
    322 * matches @doi.  The caller is responsible for calling rcu_read_[un]lock().
    323 * Returns a pointer to the DOI definition on success and NULL on failure.
    324 */
    325static struct calipso_doi *calipso_doi_search(u32 doi)
    326{
    327	struct calipso_doi *iter;
    328
    329	list_for_each_entry_rcu(iter, &calipso_doi_list, list)
    330		if (iter->doi == doi && refcount_read(&iter->refcount))
    331			return iter;
    332	return NULL;
    333}
    334
    335/**
    336 * calipso_doi_add - Add a new DOI to the CALIPSO protocol engine
    337 * @doi_def: the DOI structure
    338 * @audit_info: NetLabel audit information
    339 *
    340 * Description:
    341 * The caller defines a new DOI for use by the CALIPSO engine and calls this
    342 * function to add it to the list of acceptable domains.  The caller must
    343 * ensure that the mapping table specified in @doi_def->map meets all of the
    344 * requirements of the mapping type (see calipso.h for details).  Returns
    345 * zero on success and non-zero on failure.
    346 *
    347 */
    348static int calipso_doi_add(struct calipso_doi *doi_def,
    349			   struct netlbl_audit *audit_info)
    350{
    351	int ret_val = -EINVAL;
    352	u32 doi;
    353	u32 doi_type;
    354	struct audit_buffer *audit_buf;
    355
    356	doi = doi_def->doi;
    357	doi_type = doi_def->type;
    358
    359	if (doi_def->doi == CALIPSO_DOI_UNKNOWN)
    360		goto doi_add_return;
    361
    362	refcount_set(&doi_def->refcount, 1);
    363
    364	spin_lock(&calipso_doi_list_lock);
    365	if (calipso_doi_search(doi_def->doi)) {
    366		spin_unlock(&calipso_doi_list_lock);
    367		ret_val = -EEXIST;
    368		goto doi_add_return;
    369	}
    370	list_add_tail_rcu(&doi_def->list, &calipso_doi_list);
    371	spin_unlock(&calipso_doi_list_lock);
    372	ret_val = 0;
    373
    374doi_add_return:
    375	audit_buf = netlbl_audit_start(AUDIT_MAC_CALIPSO_ADD, audit_info);
    376	if (audit_buf) {
    377		const char *type_str;
    378
    379		switch (doi_type) {
    380		case CALIPSO_MAP_PASS:
    381			type_str = "pass";
    382			break;
    383		default:
    384			type_str = "(unknown)";
    385		}
    386		audit_log_format(audit_buf,
    387				 " calipso_doi=%u calipso_type=%s res=%u",
    388				 doi, type_str, ret_val == 0 ? 1 : 0);
    389		audit_log_end(audit_buf);
    390	}
    391
    392	return ret_val;
    393}
    394
    395/**
    396 * calipso_doi_free - Frees a DOI definition
    397 * @doi_def: the DOI definition
    398 *
    399 * Description:
    400 * This function frees all of the memory associated with a DOI definition.
    401 *
    402 */
    403static void calipso_doi_free(struct calipso_doi *doi_def)
    404{
    405	kfree(doi_def);
    406}
    407
    408/**
    409 * calipso_doi_free_rcu - Frees a DOI definition via the RCU pointer
    410 * @entry: the entry's RCU field
    411 *
    412 * Description:
    413 * This function is designed to be used as a callback to the call_rcu()
    414 * function so that the memory allocated to the DOI definition can be released
    415 * safely.
    416 *
    417 */
    418static void calipso_doi_free_rcu(struct rcu_head *entry)
    419{
    420	struct calipso_doi *doi_def;
    421
    422	doi_def = container_of(entry, struct calipso_doi, rcu);
    423	calipso_doi_free(doi_def);
    424}
    425
    426/**
    427 * calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine
    428 * @doi: the DOI value
    429 * @audit_info: NetLabel audit information
    430 *
    431 * Description:
    432 * Removes a DOI definition from the CALIPSO engine.  The NetLabel routines will
    433 * be called to release their own LSM domain mappings as well as our own
    434 * domain list.  Returns zero on success and negative values on failure.
    435 *
    436 */
    437static int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
    438{
    439	int ret_val;
    440	struct calipso_doi *doi_def;
    441	struct audit_buffer *audit_buf;
    442
    443	spin_lock(&calipso_doi_list_lock);
    444	doi_def = calipso_doi_search(doi);
    445	if (!doi_def) {
    446		spin_unlock(&calipso_doi_list_lock);
    447		ret_val = -ENOENT;
    448		goto doi_remove_return;
    449	}
    450	list_del_rcu(&doi_def->list);
    451	spin_unlock(&calipso_doi_list_lock);
    452
    453	calipso_doi_putdef(doi_def);
    454	ret_val = 0;
    455
    456doi_remove_return:
    457	audit_buf = netlbl_audit_start(AUDIT_MAC_CALIPSO_DEL, audit_info);
    458	if (audit_buf) {
    459		audit_log_format(audit_buf,
    460				 " calipso_doi=%u res=%u",
    461				 doi, ret_val == 0 ? 1 : 0);
    462		audit_log_end(audit_buf);
    463	}
    464
    465	return ret_val;
    466}
    467
    468/**
    469 * calipso_doi_getdef - Returns a reference to a valid DOI definition
    470 * @doi: the DOI value
    471 *
    472 * Description:
    473 * Searches for a valid DOI definition and if one is found it is returned to
    474 * the caller.  Otherwise NULL is returned.  The caller must ensure that
    475 * calipso_doi_putdef() is called when the caller is done.
    476 *
    477 */
    478static struct calipso_doi *calipso_doi_getdef(u32 doi)
    479{
    480	struct calipso_doi *doi_def;
    481
    482	rcu_read_lock();
    483	doi_def = calipso_doi_search(doi);
    484	if (!doi_def)
    485		goto doi_getdef_return;
    486	if (!refcount_inc_not_zero(&doi_def->refcount))
    487		doi_def = NULL;
    488
    489doi_getdef_return:
    490	rcu_read_unlock();
    491	return doi_def;
    492}
    493
    494/**
    495 * calipso_doi_putdef - Releases a reference for the given DOI definition
    496 * @doi_def: the DOI definition
    497 *
    498 * Description:
    499 * Releases a DOI definition reference obtained from calipso_doi_getdef().
    500 *
    501 */
    502static void calipso_doi_putdef(struct calipso_doi *doi_def)
    503{
    504	if (!doi_def)
    505		return;
    506
    507	if (!refcount_dec_and_test(&doi_def->refcount))
    508		return;
    509
    510	calipso_cache_invalidate();
    511	call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
    512}
    513
    514/**
    515 * calipso_doi_walk - Iterate through the DOI definitions
    516 * @skip_cnt: skip past this number of DOI definitions, updated
    517 * @callback: callback for each DOI definition
    518 * @cb_arg: argument for the callback function
    519 *
    520 * Description:
    521 * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
    522 * For each entry call @callback, if @callback returns a negative value stop
    523 * 'walking' through the list and return.  Updates the value in @skip_cnt upon
    524 * return.  Returns zero on success, negative values on failure.
    525 *
    526 */
    527static int calipso_doi_walk(u32 *skip_cnt,
    528			    int (*callback)(struct calipso_doi *doi_def,
    529					    void *arg),
    530			    void *cb_arg)
    531{
    532	int ret_val = -ENOENT;
    533	u32 doi_cnt = 0;
    534	struct calipso_doi *iter_doi;
    535
    536	rcu_read_lock();
    537	list_for_each_entry_rcu(iter_doi, &calipso_doi_list, list)
    538		if (refcount_read(&iter_doi->refcount) > 0) {
    539			if (doi_cnt++ < *skip_cnt)
    540				continue;
    541			ret_val = callback(iter_doi, cb_arg);
    542			if (ret_val < 0) {
    543				doi_cnt--;
    544				goto doi_walk_return;
    545			}
    546		}
    547
    548doi_walk_return:
    549	rcu_read_unlock();
    550	*skip_cnt = doi_cnt;
    551	return ret_val;
    552}
    553
    554/**
    555 * calipso_validate - Validate a CALIPSO option
    556 * @skb: the packet
    557 * @option: the start of the option
    558 *
    559 * Description:
    560 * This routine is called to validate a CALIPSO option.
    561 * If the option is valid then %true is returned, otherwise
    562 * %false is returned.
    563 *
    564 * The caller should have already checked that the length of the
    565 * option (including the TLV header) is >= 10 and that the catmap
    566 * length is consistent with the option length.
    567 *
    568 * We leave checks on the level and categories to the socket layer.
    569 */
    570bool calipso_validate(const struct sk_buff *skb, const unsigned char *option)
    571{
    572	struct calipso_doi *doi_def;
    573	bool ret_val;
    574	u16 crc, len = option[1] + 2;
    575	static const u8 zero[2];
    576
    577	/* The original CRC runs over the option including the TLV header
    578	 * with the CRC-16 field (at offset 8) zeroed out. */
    579	crc = crc_ccitt(0xffff, option, 8);
    580	crc = crc_ccitt(crc, zero, sizeof(zero));
    581	if (len > 10)
    582		crc = crc_ccitt(crc, option + 10, len - 10);
    583	crc = ~crc;
    584	if (option[8] != (crc & 0xff) || option[9] != ((crc >> 8) & 0xff))
    585		return false;
    586
    587	rcu_read_lock();
    588	doi_def = calipso_doi_search(get_unaligned_be32(option + 2));
    589	ret_val = !!doi_def;
    590	rcu_read_unlock();
    591
    592	return ret_val;
    593}
    594
    595/**
    596 * calipso_map_cat_hton - Perform a category mapping from host to network
    597 * @doi_def: the DOI definition
    598 * @secattr: the security attributes
    599 * @net_cat: the zero'd out category bitmap in network/CALIPSO format
    600 * @net_cat_len: the length of the CALIPSO bitmap in bytes
    601 *
    602 * Description:
    603 * Perform a label mapping to translate a local MLS category bitmap to the
    604 * correct CALIPSO bitmap using the given DOI definition.  Returns the minimum
    605 * size in bytes of the network bitmap on success, negative values otherwise.
    606 *
    607 */
    608static int calipso_map_cat_hton(const struct calipso_doi *doi_def,
    609				const struct netlbl_lsm_secattr *secattr,
    610				unsigned char *net_cat,
    611				u32 net_cat_len)
    612{
    613	int spot = -1;
    614	u32 net_spot_max = 0;
    615	u32 net_clen_bits = net_cat_len * 8;
    616
    617	for (;;) {
    618		spot = netlbl_catmap_walk(secattr->attr.mls.cat,
    619					  spot + 1);
    620		if (spot < 0)
    621			break;
    622		if (spot >= net_clen_bits)
    623			return -ENOSPC;
    624		netlbl_bitmap_setbit(net_cat, spot, 1);
    625
    626		if (spot > net_spot_max)
    627			net_spot_max = spot;
    628	}
    629
    630	return (net_spot_max / 32 + 1) * 4;
    631}
    632
    633/**
    634 * calipso_map_cat_ntoh - Perform a category mapping from network to host
    635 * @doi_def: the DOI definition
    636 * @net_cat: the category bitmap in network/CALIPSO format
    637 * @net_cat_len: the length of the CALIPSO bitmap in bytes
    638 * @secattr: the security attributes
    639 *
    640 * Description:
    641 * Perform a label mapping to translate a CALIPSO bitmap to the correct local
    642 * MLS category bitmap using the given DOI definition.  Returns zero on
    643 * success, negative values on failure.
    644 *
    645 */
    646static int calipso_map_cat_ntoh(const struct calipso_doi *doi_def,
    647				const unsigned char *net_cat,
    648				u32 net_cat_len,
    649				struct netlbl_lsm_secattr *secattr)
    650{
    651	int ret_val;
    652	int spot = -1;
    653	u32 net_clen_bits = net_cat_len * 8;
    654
    655	for (;;) {
    656		spot = netlbl_bitmap_walk(net_cat,
    657					  net_clen_bits,
    658					  spot + 1,
    659					  1);
    660		if (spot < 0) {
    661			if (spot == -2)
    662				return -EFAULT;
    663			return 0;
    664		}
    665
    666		ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
    667					       spot,
    668					       GFP_ATOMIC);
    669		if (ret_val != 0)
    670			return ret_val;
    671	}
    672
    673	return -EINVAL;
    674}
    675
    676/**
    677 * calipso_pad_write - Writes pad bytes in TLV format
    678 * @buf: the buffer
    679 * @offset: offset from start of buffer to write padding
    680 * @count: number of pad bytes to write
    681 *
    682 * Description:
    683 * Write @count bytes of TLV padding into @buffer starting at offset @offset.
    684 * @count should be less than 8 - see RFC 4942.
    685 *
    686 */
    687static int calipso_pad_write(unsigned char *buf, unsigned int offset,
    688			     unsigned int count)
    689{
    690	if (WARN_ON_ONCE(count >= 8))
    691		return -EINVAL;
    692
    693	switch (count) {
    694	case 0:
    695		break;
    696	case 1:
    697		buf[offset] = IPV6_TLV_PAD1;
    698		break;
    699	default:
    700		buf[offset] = IPV6_TLV_PADN;
    701		buf[offset + 1] = count - 2;
    702		if (count > 2)
    703			memset(buf + offset + 2, 0, count - 2);
    704		break;
    705	}
    706	return 0;
    707}
    708
    709/**
    710 * calipso_genopt - Generate a CALIPSO option
    711 * @buf: the option buffer
    712 * @start: offset from which to write
    713 * @buf_len: the size of opt_buf
    714 * @doi_def: the CALIPSO DOI to use
    715 * @secattr: the security attributes
    716 *
    717 * Description:
    718 * Generate a CALIPSO option using the DOI definition and security attributes
    719 * passed to the function. This also generates upto three bytes of leading
    720 * padding that ensures that the option is 4n + 2 aligned.  It returns the
    721 * number of bytes written (including any initial padding).
    722 */
    723static int calipso_genopt(unsigned char *buf, u32 start, u32 buf_len,
    724			  const struct calipso_doi *doi_def,
    725			  const struct netlbl_lsm_secattr *secattr)
    726{
    727	int ret_val;
    728	u32 len, pad;
    729	u16 crc;
    730	static const unsigned char padding[4] = {2, 1, 0, 3};
    731	unsigned char *calipso;
    732
    733	/* CALIPSO has 4n + 2 alignment */
    734	pad = padding[start & 3];
    735	if (buf_len <= start + pad + CALIPSO_HDR_LEN)
    736		return -ENOSPC;
    737
    738	if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0)
    739		return -EPERM;
    740
    741	len = CALIPSO_HDR_LEN;
    742
    743	if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
    744		ret_val = calipso_map_cat_hton(doi_def,
    745					       secattr,
    746					       buf + start + pad + len,
    747					       buf_len - start - pad - len);
    748		if (ret_val < 0)
    749			return ret_val;
    750		len += ret_val;
    751	}
    752
    753	calipso_pad_write(buf, start, pad);
    754	calipso = buf + start + pad;
    755
    756	calipso[0] = IPV6_TLV_CALIPSO;
    757	calipso[1] = len - 2;
    758	*(__be32 *)(calipso + 2) = htonl(doi_def->doi);
    759	calipso[6] = (len - CALIPSO_HDR_LEN) / 4;
    760	calipso[7] = secattr->attr.mls.lvl;
    761	crc = ~crc_ccitt(0xffff, calipso, len);
    762	calipso[8] = crc & 0xff;
    763	calipso[9] = (crc >> 8) & 0xff;
    764	return pad + len;
    765}
    766
    767/* Hop-by-hop hdr helper functions
    768 */
    769
    770/**
    771 * calipso_opt_update - Replaces socket's hop options with a new set
    772 * @sk: the socket
    773 * @hop: new hop options
    774 *
    775 * Description:
    776 * Replaces @sk's hop options with @hop.  @hop may be NULL to leave
    777 * the socket with no hop options.
    778 *
    779 */
    780static int calipso_opt_update(struct sock *sk, struct ipv6_opt_hdr *hop)
    781{
    782	struct ipv6_txoptions *old = txopt_get(inet6_sk(sk)), *txopts;
    783
    784	txopts = ipv6_renew_options(sk, old, IPV6_HOPOPTS, hop);
    785	txopt_put(old);
    786	if (IS_ERR(txopts))
    787		return PTR_ERR(txopts);
    788
    789	txopts = ipv6_update_options(sk, txopts);
    790	if (txopts) {
    791		atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
    792		txopt_put(txopts);
    793	}
    794
    795	return 0;
    796}
    797
    798/**
    799 * calipso_tlv_len - Returns the length of the TLV
    800 * @opt: the option header
    801 * @offset: offset of the TLV within the header
    802 *
    803 * Description:
    804 * Returns the length of the TLV option at offset @offset within
    805 * the option header @opt.  Checks that the entire TLV fits inside
    806 * the option header, returns a negative value if this is not the case.
    807 */
    808static int calipso_tlv_len(struct ipv6_opt_hdr *opt, unsigned int offset)
    809{
    810	unsigned char *tlv = (unsigned char *)opt;
    811	unsigned int opt_len = ipv6_optlen(opt), tlv_len;
    812
    813	if (offset < sizeof(*opt) || offset >= opt_len)
    814		return -EINVAL;
    815	if (tlv[offset] == IPV6_TLV_PAD1)
    816		return 1;
    817	if (offset + 1 >= opt_len)
    818		return -EINVAL;
    819	tlv_len = tlv[offset + 1] + 2;
    820	if (offset + tlv_len > opt_len)
    821		return -EINVAL;
    822	return tlv_len;
    823}
    824
    825/**
    826 * calipso_opt_find - Finds the CALIPSO option in an IPv6 hop options header
    827 * @hop: the hop options header
    828 * @start: on return holds the offset of any leading padding
    829 * @end: on return holds the offset of the first non-pad TLV after CALIPSO
    830 *
    831 * Description:
    832 * Finds the space occupied by a CALIPSO option (including any leading and
    833 * trailing padding).
    834 *
    835 * If a CALIPSO option exists set @start and @end to the
    836 * offsets within @hop of the start of padding before the first
    837 * CALIPSO option and the end of padding after the first CALIPSO
    838 * option.  In this case the function returns 0.
    839 *
    840 * In the absence of a CALIPSO option, @start and @end will be
    841 * set to the start and end of any trailing padding in the header.
    842 * This is useful when appending a new option, as the caller may want
    843 * to overwrite some of this padding.  In this case the function will
    844 * return -ENOENT.
    845 */
    846static int calipso_opt_find(struct ipv6_opt_hdr *hop, unsigned int *start,
    847			    unsigned int *end)
    848{
    849	int ret_val = -ENOENT, tlv_len;
    850	unsigned int opt_len, offset, offset_s = 0, offset_e = 0;
    851	unsigned char *opt = (unsigned char *)hop;
    852
    853	opt_len = ipv6_optlen(hop);
    854	offset = sizeof(*hop);
    855
    856	while (offset < opt_len) {
    857		tlv_len = calipso_tlv_len(hop, offset);
    858		if (tlv_len < 0)
    859			return tlv_len;
    860
    861		switch (opt[offset]) {
    862		case IPV6_TLV_PAD1:
    863		case IPV6_TLV_PADN:
    864			if (offset_e)
    865				offset_e = offset;
    866			break;
    867		case IPV6_TLV_CALIPSO:
    868			ret_val = 0;
    869			offset_e = offset;
    870			break;
    871		default:
    872			if (offset_e == 0)
    873				offset_s = offset;
    874			else
    875				goto out;
    876		}
    877		offset += tlv_len;
    878	}
    879
    880out:
    881	if (offset_s)
    882		*start = offset_s + calipso_tlv_len(hop, offset_s);
    883	else
    884		*start = sizeof(*hop);
    885	if (offset_e)
    886		*end = offset_e + calipso_tlv_len(hop, offset_e);
    887	else
    888		*end = opt_len;
    889
    890	return ret_val;
    891}
    892
    893/**
    894 * calipso_opt_insert - Inserts a CALIPSO option into an IPv6 hop opt hdr
    895 * @hop: the original hop options header
    896 * @doi_def: the CALIPSO DOI to use
    897 * @secattr: the specific security attributes of the socket
    898 *
    899 * Description:
    900 * Creates a new hop options header based on @hop with a
    901 * CALIPSO option added to it.  If @hop already contains a CALIPSO
    902 * option this is overwritten, otherwise the new option is appended
    903 * after any existing options.  If @hop is NULL then the new header
    904 * will contain just the CALIPSO option and any needed padding.
    905 *
    906 */
    907static struct ipv6_opt_hdr *
    908calipso_opt_insert(struct ipv6_opt_hdr *hop,
    909		   const struct calipso_doi *doi_def,
    910		   const struct netlbl_lsm_secattr *secattr)
    911{
    912	unsigned int start, end, buf_len, pad, hop_len;
    913	struct ipv6_opt_hdr *new;
    914	int ret_val;
    915
    916	if (hop) {
    917		hop_len = ipv6_optlen(hop);
    918		ret_val = calipso_opt_find(hop, &start, &end);
    919		if (ret_val && ret_val != -ENOENT)
    920			return ERR_PTR(ret_val);
    921	} else {
    922		hop_len = 0;
    923		start = sizeof(*hop);
    924		end = 0;
    925	}
    926
    927	buf_len = hop_len + start - end + CALIPSO_OPT_LEN_MAX_WITH_PAD;
    928	new = kzalloc(buf_len, GFP_ATOMIC);
    929	if (!new)
    930		return ERR_PTR(-ENOMEM);
    931
    932	if (start > sizeof(*hop))
    933		memcpy(new, hop, start);
    934	ret_val = calipso_genopt((unsigned char *)new, start, buf_len, doi_def,
    935				 secattr);
    936	if (ret_val < 0) {
    937		kfree(new);
    938		return ERR_PTR(ret_val);
    939	}
    940
    941	buf_len = start + ret_val;
    942	/* At this point buf_len aligns to 4n, so (buf_len & 4) pads to 8n */
    943	pad = ((buf_len & 4) + (end & 7)) & 7;
    944	calipso_pad_write((unsigned char *)new, buf_len, pad);
    945	buf_len += pad;
    946
    947	if (end != hop_len) {
    948		memcpy((char *)new + buf_len, (char *)hop + end, hop_len - end);
    949		buf_len += hop_len - end;
    950	}
    951	new->nexthdr = 0;
    952	new->hdrlen = buf_len / 8 - 1;
    953
    954	return new;
    955}
    956
    957/**
    958 * calipso_opt_del - Removes the CALIPSO option from an option header
    959 * @hop: the original header
    960 * @new: the new header
    961 *
    962 * Description:
    963 * Creates a new header based on @hop without any CALIPSO option.  If @hop
    964 * doesn't contain a CALIPSO option it returns -ENOENT.  If @hop contains
    965 * no other non-padding options, it returns zero with @new set to NULL.
    966 * Otherwise it returns zero, creates a new header without the CALIPSO
    967 * option (and removing as much padding as possible) and returns with
    968 * @new set to that header.
    969 *
    970 */
    971static int calipso_opt_del(struct ipv6_opt_hdr *hop,
    972			   struct ipv6_opt_hdr **new)
    973{
    974	int ret_val;
    975	unsigned int start, end, delta, pad, hop_len;
    976
    977	ret_val = calipso_opt_find(hop, &start, &end);
    978	if (ret_val)
    979		return ret_val;
    980
    981	hop_len = ipv6_optlen(hop);
    982	if (start == sizeof(*hop) && end == hop_len) {
    983		/* There's no other option in the header so return NULL */
    984		*new = NULL;
    985		return 0;
    986	}
    987
    988	delta = (end - start) & ~7;
    989	*new = kzalloc(hop_len - delta, GFP_ATOMIC);
    990	if (!*new)
    991		return -ENOMEM;
    992
    993	memcpy(*new, hop, start);
    994	(*new)->hdrlen -= delta / 8;
    995	pad = (end - start) & 7;
    996	calipso_pad_write((unsigned char *)*new, start, pad);
    997	if (end != hop_len)
    998		memcpy((char *)*new + start + pad, (char *)hop + end,
    999		       hop_len - end);
   1000
   1001	return 0;
   1002}
   1003
   1004/**
   1005 * calipso_opt_getattr - Get the security attributes from a memory block
   1006 * @calipso: the CALIPSO option
   1007 * @secattr: the security attributes
   1008 *
   1009 * Description:
   1010 * Inspect @calipso and return the security attributes in @secattr.
   1011 * Returns zero on success and negative values on failure.
   1012 *
   1013 */
   1014static int calipso_opt_getattr(const unsigned char *calipso,
   1015			       struct netlbl_lsm_secattr *secattr)
   1016{
   1017	int ret_val = -ENOMSG;
   1018	u32 doi, len = calipso[1], cat_len = calipso[6] * 4;
   1019	struct calipso_doi *doi_def;
   1020
   1021	if (cat_len + 8 > len)
   1022		return -EINVAL;
   1023
   1024	if (calipso_cache_check(calipso + 2, calipso[1], secattr) == 0)
   1025		return 0;
   1026
   1027	doi = get_unaligned_be32(calipso + 2);
   1028	rcu_read_lock();
   1029	doi_def = calipso_doi_search(doi);
   1030	if (!doi_def)
   1031		goto getattr_return;
   1032
   1033	secattr->attr.mls.lvl = calipso[7];
   1034	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
   1035
   1036	if (cat_len) {
   1037		ret_val = calipso_map_cat_ntoh(doi_def,
   1038					       calipso + 10,
   1039					       cat_len,
   1040					       secattr);
   1041		if (ret_val != 0) {
   1042			netlbl_catmap_free(secattr->attr.mls.cat);
   1043			goto getattr_return;
   1044		}
   1045
   1046		if (secattr->attr.mls.cat)
   1047			secattr->flags |= NETLBL_SECATTR_MLS_CAT;
   1048	}
   1049
   1050	secattr->type = NETLBL_NLTYPE_CALIPSO;
   1051
   1052getattr_return:
   1053	rcu_read_unlock();
   1054	return ret_val;
   1055}
   1056
   1057/* sock functions.
   1058 */
   1059
   1060/**
   1061 * calipso_sock_getattr - Get the security attributes from a sock
   1062 * @sk: the sock
   1063 * @secattr: the security attributes
   1064 *
   1065 * Description:
   1066 * Query @sk to see if there is a CALIPSO option attached to the sock and if
   1067 * there is return the CALIPSO security attributes in @secattr.  This function
   1068 * requires that @sk be locked, or privately held, but it does not do any
   1069 * locking itself.  Returns zero on success and negative values on failure.
   1070 *
   1071 */
   1072static int calipso_sock_getattr(struct sock *sk,
   1073				struct netlbl_lsm_secattr *secattr)
   1074{
   1075	struct ipv6_opt_hdr *hop;
   1076	int opt_len, len, ret_val = -ENOMSG, offset;
   1077	unsigned char *opt;
   1078	struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
   1079
   1080	if (!txopts || !txopts->hopopt)
   1081		goto done;
   1082
   1083	hop = txopts->hopopt;
   1084	opt = (unsigned char *)hop;
   1085	opt_len = ipv6_optlen(hop);
   1086	offset = sizeof(*hop);
   1087	while (offset < opt_len) {
   1088		len = calipso_tlv_len(hop, offset);
   1089		if (len < 0) {
   1090			ret_val = len;
   1091			goto done;
   1092		}
   1093		switch (opt[offset]) {
   1094		case IPV6_TLV_CALIPSO:
   1095			if (len < CALIPSO_HDR_LEN)
   1096				ret_val = -EINVAL;
   1097			else
   1098				ret_val = calipso_opt_getattr(&opt[offset],
   1099							      secattr);
   1100			goto done;
   1101		default:
   1102			offset += len;
   1103			break;
   1104		}
   1105	}
   1106done:
   1107	txopt_put(txopts);
   1108	return ret_val;
   1109}
   1110
   1111/**
   1112 * calipso_sock_setattr - Add a CALIPSO option to a socket
   1113 * @sk: the socket
   1114 * @doi_def: the CALIPSO DOI to use
   1115 * @secattr: the specific security attributes of the socket
   1116 *
   1117 * Description:
   1118 * Set the CALIPSO option on the given socket using the DOI definition and
   1119 * security attributes passed to the function.  This function requires
   1120 * exclusive access to @sk, which means it either needs to be in the
   1121 * process of being created or locked.  Returns zero on success and negative
   1122 * values on failure.
   1123 *
   1124 */
   1125static int calipso_sock_setattr(struct sock *sk,
   1126				const struct calipso_doi *doi_def,
   1127				const struct netlbl_lsm_secattr *secattr)
   1128{
   1129	int ret_val;
   1130	struct ipv6_opt_hdr *old, *new;
   1131	struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
   1132
   1133	old = NULL;
   1134	if (txopts)
   1135		old = txopts->hopopt;
   1136
   1137	new = calipso_opt_insert(old, doi_def, secattr);
   1138	txopt_put(txopts);
   1139	if (IS_ERR(new))
   1140		return PTR_ERR(new);
   1141
   1142	ret_val = calipso_opt_update(sk, new);
   1143
   1144	kfree(new);
   1145	return ret_val;
   1146}
   1147
   1148/**
   1149 * calipso_sock_delattr - Delete the CALIPSO option from a socket
   1150 * @sk: the socket
   1151 *
   1152 * Description:
   1153 * Removes the CALIPSO option from a socket, if present.
   1154 *
   1155 */
   1156static void calipso_sock_delattr(struct sock *sk)
   1157{
   1158	struct ipv6_opt_hdr *new_hop;
   1159	struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
   1160
   1161	if (!txopts || !txopts->hopopt)
   1162		goto done;
   1163
   1164	if (calipso_opt_del(txopts->hopopt, &new_hop))
   1165		goto done;
   1166
   1167	calipso_opt_update(sk, new_hop);
   1168	kfree(new_hop);
   1169
   1170done:
   1171	txopt_put(txopts);
   1172}
   1173
   1174/* request sock functions.
   1175 */
   1176
   1177/**
   1178 * calipso_req_setattr - Add a CALIPSO option to a connection request socket
   1179 * @req: the connection request socket
   1180 * @doi_def: the CALIPSO DOI to use
   1181 * @secattr: the specific security attributes of the socket
   1182 *
   1183 * Description:
   1184 * Set the CALIPSO option on the given socket using the DOI definition and
   1185 * security attributes passed to the function.  Returns zero on success and
   1186 * negative values on failure.
   1187 *
   1188 */
   1189static int calipso_req_setattr(struct request_sock *req,
   1190			       const struct calipso_doi *doi_def,
   1191			       const struct netlbl_lsm_secattr *secattr)
   1192{
   1193	struct ipv6_txoptions *txopts;
   1194	struct inet_request_sock *req_inet = inet_rsk(req);
   1195	struct ipv6_opt_hdr *old, *new;
   1196	struct sock *sk = sk_to_full_sk(req_to_sk(req));
   1197
   1198	if (req_inet->ipv6_opt && req_inet->ipv6_opt->hopopt)
   1199		old = req_inet->ipv6_opt->hopopt;
   1200	else
   1201		old = NULL;
   1202
   1203	new = calipso_opt_insert(old, doi_def, secattr);
   1204	if (IS_ERR(new))
   1205		return PTR_ERR(new);
   1206
   1207	txopts = ipv6_renew_options(sk, req_inet->ipv6_opt, IPV6_HOPOPTS, new);
   1208
   1209	kfree(new);
   1210
   1211	if (IS_ERR(txopts))
   1212		return PTR_ERR(txopts);
   1213
   1214	txopts = xchg(&req_inet->ipv6_opt, txopts);
   1215	if (txopts) {
   1216		atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
   1217		txopt_put(txopts);
   1218	}
   1219
   1220	return 0;
   1221}
   1222
   1223/**
   1224 * calipso_req_delattr - Delete the CALIPSO option from a request socket
   1225 * @req: the request socket
   1226 *
   1227 * Description:
   1228 * Removes the CALIPSO option from a request socket, if present.
   1229 *
   1230 */
   1231static void calipso_req_delattr(struct request_sock *req)
   1232{
   1233	struct inet_request_sock *req_inet = inet_rsk(req);
   1234	struct ipv6_opt_hdr *new;
   1235	struct ipv6_txoptions *txopts;
   1236	struct sock *sk = sk_to_full_sk(req_to_sk(req));
   1237
   1238	if (!req_inet->ipv6_opt || !req_inet->ipv6_opt->hopopt)
   1239		return;
   1240
   1241	if (calipso_opt_del(req_inet->ipv6_opt->hopopt, &new))
   1242		return; /* Nothing to do */
   1243
   1244	txopts = ipv6_renew_options(sk, req_inet->ipv6_opt, IPV6_HOPOPTS, new);
   1245
   1246	if (!IS_ERR(txopts)) {
   1247		txopts = xchg(&req_inet->ipv6_opt, txopts);
   1248		if (txopts) {
   1249			atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
   1250			txopt_put(txopts);
   1251		}
   1252	}
   1253	kfree(new);
   1254}
   1255
   1256/* skbuff functions.
   1257 */
   1258
   1259/**
   1260 * calipso_skbuff_optptr - Find the CALIPSO option in the packet
   1261 * @skb: the packet
   1262 *
   1263 * Description:
   1264 * Parse the packet's IP header looking for a CALIPSO option.  Returns a pointer
   1265 * to the start of the CALIPSO option on success, NULL if one if not found.
   1266 *
   1267 */
   1268static unsigned char *calipso_skbuff_optptr(const struct sk_buff *skb)
   1269{
   1270	const struct ipv6hdr *ip6_hdr = ipv6_hdr(skb);
   1271	int offset;
   1272
   1273	if (ip6_hdr->nexthdr != NEXTHDR_HOP)
   1274		return NULL;
   1275
   1276	offset = ipv6_find_tlv(skb, sizeof(*ip6_hdr), IPV6_TLV_CALIPSO);
   1277	if (offset >= 0)
   1278		return (unsigned char *)ip6_hdr + offset;
   1279
   1280	return NULL;
   1281}
   1282
   1283/**
   1284 * calipso_skbuff_setattr - Set the CALIPSO option on a packet
   1285 * @skb: the packet
   1286 * @doi_def: the CALIPSO DOI to use
   1287 * @secattr: the security attributes
   1288 *
   1289 * Description:
   1290 * Set the CALIPSO option on the given packet based on the security attributes.
   1291 * Returns a pointer to the IP header on success and NULL on failure.
   1292 *
   1293 */
   1294static int calipso_skbuff_setattr(struct sk_buff *skb,
   1295				  const struct calipso_doi *doi_def,
   1296				  const struct netlbl_lsm_secattr *secattr)
   1297{
   1298	int ret_val;
   1299	struct ipv6hdr *ip6_hdr;
   1300	struct ipv6_opt_hdr *hop;
   1301	unsigned char buf[CALIPSO_MAX_BUFFER];
   1302	int len_delta, new_end, pad, payload;
   1303	unsigned int start, end;
   1304
   1305	ip6_hdr = ipv6_hdr(skb);
   1306	if (ip6_hdr->nexthdr == NEXTHDR_HOP) {
   1307		hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
   1308		ret_val = calipso_opt_find(hop, &start, &end);
   1309		if (ret_val && ret_val != -ENOENT)
   1310			return ret_val;
   1311	} else {
   1312		start = 0;
   1313		end = 0;
   1314	}
   1315
   1316	memset(buf, 0, sizeof(buf));
   1317	ret_val = calipso_genopt(buf, start & 3, sizeof(buf), doi_def, secattr);
   1318	if (ret_val < 0)
   1319		return ret_val;
   1320
   1321	new_end = start + ret_val;
   1322	/* At this point new_end aligns to 4n, so (new_end & 4) pads to 8n */
   1323	pad = ((new_end & 4) + (end & 7)) & 7;
   1324	len_delta = new_end - (int)end + pad;
   1325	ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
   1326	if (ret_val < 0)
   1327		return ret_val;
   1328
   1329	ip6_hdr = ipv6_hdr(skb); /* Reset as skb_cow() may have moved it */
   1330
   1331	if (len_delta) {
   1332		if (len_delta > 0)
   1333			skb_push(skb, len_delta);
   1334		else
   1335			skb_pull(skb, -len_delta);
   1336		memmove((char *)ip6_hdr - len_delta, ip6_hdr,
   1337			sizeof(*ip6_hdr) + start);
   1338		skb_reset_network_header(skb);
   1339		ip6_hdr = ipv6_hdr(skb);
   1340		payload = ntohs(ip6_hdr->payload_len);
   1341		ip6_hdr->payload_len = htons(payload + len_delta);
   1342	}
   1343
   1344	hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
   1345	if (start == 0) {
   1346		struct ipv6_opt_hdr *new_hop = (struct ipv6_opt_hdr *)buf;
   1347
   1348		new_hop->nexthdr = ip6_hdr->nexthdr;
   1349		new_hop->hdrlen = len_delta / 8 - 1;
   1350		ip6_hdr->nexthdr = NEXTHDR_HOP;
   1351	} else {
   1352		hop->hdrlen += len_delta / 8;
   1353	}
   1354	memcpy((char *)hop + start, buf + (start & 3), new_end - start);
   1355	calipso_pad_write((unsigned char *)hop, new_end, pad);
   1356
   1357	return 0;
   1358}
   1359
   1360/**
   1361 * calipso_skbuff_delattr - Delete any CALIPSO options from a packet
   1362 * @skb: the packet
   1363 *
   1364 * Description:
   1365 * Removes any and all CALIPSO options from the given packet.  Returns zero on
   1366 * success, negative values on failure.
   1367 *
   1368 */
   1369static int calipso_skbuff_delattr(struct sk_buff *skb)
   1370{
   1371	int ret_val;
   1372	struct ipv6hdr *ip6_hdr;
   1373	struct ipv6_opt_hdr *old_hop;
   1374	u32 old_hop_len, start = 0, end = 0, delta, size, pad;
   1375
   1376	if (!calipso_skbuff_optptr(skb))
   1377		return 0;
   1378
   1379	/* since we are changing the packet we should make a copy */
   1380	ret_val = skb_cow(skb, skb_headroom(skb));
   1381	if (ret_val < 0)
   1382		return ret_val;
   1383
   1384	ip6_hdr = ipv6_hdr(skb);
   1385	old_hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
   1386	old_hop_len = ipv6_optlen(old_hop);
   1387
   1388	ret_val = calipso_opt_find(old_hop, &start, &end);
   1389	if (ret_val)
   1390		return ret_val;
   1391
   1392	if (start == sizeof(*old_hop) && end == old_hop_len) {
   1393		/* There's no other option in the header so we delete
   1394		 * the whole thing. */
   1395		delta = old_hop_len;
   1396		size = sizeof(*ip6_hdr);
   1397		ip6_hdr->nexthdr = old_hop->nexthdr;
   1398	} else {
   1399		delta = (end - start) & ~7;
   1400		if (delta)
   1401			old_hop->hdrlen -= delta / 8;
   1402		pad = (end - start) & 7;
   1403		size = sizeof(*ip6_hdr) + start + pad;
   1404		calipso_pad_write((unsigned char *)old_hop, start, pad);
   1405	}
   1406
   1407	if (delta) {
   1408		skb_pull(skb, delta);
   1409		memmove((char *)ip6_hdr + delta, ip6_hdr, size);
   1410		skb_reset_network_header(skb);
   1411	}
   1412
   1413	return 0;
   1414}
   1415
   1416static const struct netlbl_calipso_ops ops = {
   1417	.doi_add          = calipso_doi_add,
   1418	.doi_free         = calipso_doi_free,
   1419	.doi_remove       = calipso_doi_remove,
   1420	.doi_getdef       = calipso_doi_getdef,
   1421	.doi_putdef       = calipso_doi_putdef,
   1422	.doi_walk         = calipso_doi_walk,
   1423	.sock_getattr     = calipso_sock_getattr,
   1424	.sock_setattr     = calipso_sock_setattr,
   1425	.sock_delattr     = calipso_sock_delattr,
   1426	.req_setattr      = calipso_req_setattr,
   1427	.req_delattr      = calipso_req_delattr,
   1428	.opt_getattr      = calipso_opt_getattr,
   1429	.skbuff_optptr    = calipso_skbuff_optptr,
   1430	.skbuff_setattr   = calipso_skbuff_setattr,
   1431	.skbuff_delattr   = calipso_skbuff_delattr,
   1432	.cache_invalidate = calipso_cache_invalidate,
   1433	.cache_add        = calipso_cache_add
   1434};
   1435
   1436/**
   1437 * calipso_init - Initialize the CALIPSO module
   1438 *
   1439 * Description:
   1440 * Initialize the CALIPSO module and prepare it for use.  Returns zero on
   1441 * success and negative values on failure.
   1442 *
   1443 */
   1444int __init calipso_init(void)
   1445{
   1446	int ret_val;
   1447
   1448	ret_val = calipso_cache_init();
   1449	if (!ret_val)
   1450		netlbl_calipso_ops_register(&ops);
   1451	return ret_val;
   1452}
   1453
   1454void calipso_exit(void)
   1455{
   1456	netlbl_calipso_ops_register(NULL);
   1457	calipso_cache_invalidate();
   1458	kfree(calipso_cache);
   1459}