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