2 * CALIPSO - Common Architecture Label IPv6 Security Option
4 * This is an implementation of the CALIPSO protocol as specified in
7 * Authors: Paul Moore <paul.moore@hp.com>
8 * Huw Davies <huw@codeweavers.com>
12 /* (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
13 * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
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.
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.
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/>.
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>
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>
49 /* Maximium size of the calipso option including
50 * the two-byte TLV header.
52 #define CALIPSO_OPT_LEN_MAX (2 + 252)
54 /* Size of the minimum calipso option including
55 * the two-byte TLV header.
57 #define CALIPSO_HDR_LEN (2 + 8)
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.
63 #define CALIPSO_OPT_LEN_MAX_WITH_PAD (3 + CALIPSO_OPT_LEN_MAX + 7)
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.
69 #define CALIPSO_MAX_BUFFER (6 + CALIPSO_OPT_LEN_MAX)
71 /* List of available DOI definitions */
72 static DEFINE_SPINLOCK(calipso_doi_list_lock);
73 static LIST_HEAD(calipso_doi_list);
79 * calipso_doi_search - Searches for a DOI definition
80 * @doi: the DOI to search for
83 * Search the DOI definition list for a DOI definition with a DOI value that
84 * matches @doi. The caller is responsible for calling rcu_read_[un]lock().
85 * Returns a pointer to the DOI definition on success and NULL on failure.
87 static struct calipso_doi *calipso_doi_search(u32 doi)
89 struct calipso_doi *iter;
91 list_for_each_entry_rcu(iter, &calipso_doi_list, list)
92 if (iter->doi == doi && atomic_read(&iter->refcount))
98 * calipso_doi_add - Add a new DOI to the CALIPSO protocol engine
99 * @doi_def: the DOI structure
100 * @audit_info: NetLabel audit information
103 * The caller defines a new DOI for use by the CALIPSO engine and calls this
104 * function to add it to the list of acceptable domains. The caller must
105 * ensure that the mapping table specified in @doi_def->map meets all of the
106 * requirements of the mapping type (see calipso.h for details). Returns
107 * zero on success and non-zero on failure.
110 static int calipso_doi_add(struct calipso_doi *doi_def,
111 struct netlbl_audit *audit_info)
113 int ret_val = -EINVAL;
116 struct audit_buffer *audit_buf;
119 doi_type = doi_def->type;
121 if (doi_def->doi == CALIPSO_DOI_UNKNOWN)
124 atomic_set(&doi_def->refcount, 1);
126 spin_lock(&calipso_doi_list_lock);
127 if (calipso_doi_search(doi_def->doi)) {
128 spin_unlock(&calipso_doi_list_lock);
132 list_add_tail_rcu(&doi_def->list, &calipso_doi_list);
133 spin_unlock(&calipso_doi_list_lock);
137 audit_buf = netlbl_audit_start(AUDIT_MAC_CALIPSO_ADD, audit_info);
139 const char *type_str;
142 case CALIPSO_MAP_PASS:
146 type_str = "(unknown)";
148 audit_log_format(audit_buf,
149 " calipso_doi=%u calipso_type=%s res=%u",
150 doi, type_str, ret_val == 0 ? 1 : 0);
151 audit_log_end(audit_buf);
158 * calipso_doi_free - Frees a DOI definition
159 * @doi_def: the DOI definition
162 * This function frees all of the memory associated with a DOI definition.
165 static void calipso_doi_free(struct calipso_doi *doi_def)
171 * calipso_doi_free_rcu - Frees a DOI definition via the RCU pointer
172 * @entry: the entry's RCU field
175 * This function is designed to be used as a callback to the call_rcu()
176 * function so that the memory allocated to the DOI definition can be released
180 static void calipso_doi_free_rcu(struct rcu_head *entry)
182 struct calipso_doi *doi_def;
184 doi_def = container_of(entry, struct calipso_doi, rcu);
185 calipso_doi_free(doi_def);
189 * calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine
190 * @doi: the DOI value
191 * @audit_secid: the LSM secid to use in the audit message
194 * Removes a DOI definition from the CALIPSO engine. The NetLabel routines will
195 * be called to release their own LSM domain mappings as well as our own
196 * domain list. Returns zero on success and negative values on failure.
199 static int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
202 struct calipso_doi *doi_def;
203 struct audit_buffer *audit_buf;
205 spin_lock(&calipso_doi_list_lock);
206 doi_def = calipso_doi_search(doi);
208 spin_unlock(&calipso_doi_list_lock);
210 goto doi_remove_return;
212 if (!atomic_dec_and_test(&doi_def->refcount)) {
213 spin_unlock(&calipso_doi_list_lock);
215 goto doi_remove_return;
217 list_del_rcu(&doi_def->list);
218 spin_unlock(&calipso_doi_list_lock);
220 call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
224 audit_buf = netlbl_audit_start(AUDIT_MAC_CALIPSO_DEL, audit_info);
226 audit_log_format(audit_buf,
227 " calipso_doi=%u res=%u",
228 doi, ret_val == 0 ? 1 : 0);
229 audit_log_end(audit_buf);
236 * calipso_doi_getdef - Returns a reference to a valid DOI definition
237 * @doi: the DOI value
240 * Searches for a valid DOI definition and if one is found it is returned to
241 * the caller. Otherwise NULL is returned. The caller must ensure that
242 * calipso_doi_putdef() is called when the caller is done.
245 static struct calipso_doi *calipso_doi_getdef(u32 doi)
247 struct calipso_doi *doi_def;
250 doi_def = calipso_doi_search(doi);
252 goto doi_getdef_return;
253 if (!atomic_inc_not_zero(&doi_def->refcount))
262 * calipso_doi_putdef - Releases a reference for the given DOI definition
263 * @doi_def: the DOI definition
266 * Releases a DOI definition reference obtained from calipso_doi_getdef().
269 static void calipso_doi_putdef(struct calipso_doi *doi_def)
274 if (!atomic_dec_and_test(&doi_def->refcount))
276 spin_lock(&calipso_doi_list_lock);
277 list_del_rcu(&doi_def->list);
278 spin_unlock(&calipso_doi_list_lock);
280 call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
284 * calipso_doi_walk - Iterate through the DOI definitions
285 * @skip_cnt: skip past this number of DOI definitions, updated
286 * @callback: callback for each DOI definition
287 * @cb_arg: argument for the callback function
290 * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
291 * For each entry call @callback, if @callback returns a negative value stop
292 * 'walking' through the list and return. Updates the value in @skip_cnt upon
293 * return. Returns zero on success, negative values on failure.
296 static int calipso_doi_walk(u32 *skip_cnt,
297 int (*callback)(struct calipso_doi *doi_def,
301 int ret_val = -ENOENT;
303 struct calipso_doi *iter_doi;
306 list_for_each_entry_rcu(iter_doi, &calipso_doi_list, list)
307 if (atomic_read(&iter_doi->refcount) > 0) {
308 if (doi_cnt++ < *skip_cnt)
310 ret_val = callback(iter_doi, cb_arg);
313 goto doi_walk_return;
324 * calipso_map_cat_hton - Perform a category mapping from host to network
325 * @doi_def: the DOI definition
326 * @secattr: the security attributes
327 * @net_cat: the zero'd out category bitmap in network/CALIPSO format
328 * @net_cat_len: the length of the CALIPSO bitmap in bytes
331 * Perform a label mapping to translate a local MLS category bitmap to the
332 * correct CALIPSO bitmap using the given DOI definition. Returns the minimum
333 * size in bytes of the network bitmap on success, negative values otherwise.
336 static int calipso_map_cat_hton(const struct calipso_doi *doi_def,
337 const struct netlbl_lsm_secattr *secattr,
338 unsigned char *net_cat,
342 u32 net_spot_max = 0;
343 u32 net_clen_bits = net_cat_len * 8;
346 spot = netlbl_catmap_walk(secattr->attr.mls.cat,
350 if (spot >= net_clen_bits)
352 netlbl_bitmap_setbit(net_cat, spot, 1);
354 if (spot > net_spot_max)
358 return (net_spot_max / 32 + 1) * 4;
362 * calipso_map_cat_ntoh - Perform a category mapping from network to host
363 * @doi_def: the DOI definition
364 * @net_cat: the category bitmap in network/CALIPSO format
365 * @net_cat_len: the length of the CALIPSO bitmap in bytes
366 * @secattr: the security attributes
369 * Perform a label mapping to translate a CALIPSO bitmap to the correct local
370 * MLS category bitmap using the given DOI definition. Returns zero on
371 * success, negative values on failure.
374 static int calipso_map_cat_ntoh(const struct calipso_doi *doi_def,
375 const unsigned char *net_cat,
377 struct netlbl_lsm_secattr *secattr)
381 u32 net_clen_bits = net_cat_len * 8;
384 spot = netlbl_bitmap_walk(net_cat,
394 ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
405 * calipso_pad_write - Writes pad bytes in TLV format
407 * @offset: offset from start of buffer to write padding
408 * @count: number of pad bytes to write
411 * Write @count bytes of TLV padding into @buffer starting at offset @offset.
412 * @count should be less than 8 - see RFC 4942.
415 static int calipso_pad_write(unsigned char *buf, unsigned int offset,
418 if (WARN_ON_ONCE(count >= 8))
425 buf[offset] = IPV6_TLV_PAD1;
428 buf[offset] = IPV6_TLV_PADN;
429 buf[offset + 1] = count - 2;
431 memset(buf + offset + 2, 0, count - 2);
438 * calipso_genopt - Generate a CALIPSO option
439 * @buf: the option buffer
440 * @start: offset from which to write
441 * @buf_len: the size of opt_buf
442 * @doi_def: the CALIPSO DOI to use
443 * @secattr: the security attributes
446 * Generate a CALIPSO option using the DOI definition and security attributes
447 * passed to the function. This also generates upto three bytes of leading
448 * padding that ensures that the option is 4n + 2 aligned. It returns the
449 * number of bytes written (including any initial padding).
451 static int calipso_genopt(unsigned char *buf, u32 start, u32 buf_len,
452 const struct calipso_doi *doi_def,
453 const struct netlbl_lsm_secattr *secattr)
458 static const unsigned char padding[4] = {2, 1, 0, 3};
459 unsigned char *calipso;
461 /* CALIPSO has 4n + 2 alignment */
462 pad = padding[start & 3];
463 if (buf_len <= start + pad + CALIPSO_HDR_LEN)
466 if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0)
469 len = CALIPSO_HDR_LEN;
471 if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
472 ret_val = calipso_map_cat_hton(doi_def,
474 buf + start + pad + len,
475 buf_len - start - pad - len);
481 calipso_pad_write(buf, start, pad);
482 calipso = buf + start + pad;
484 calipso[0] = IPV6_TLV_CALIPSO;
485 calipso[1] = len - 2;
486 *(__be32 *)(calipso + 2) = htonl(doi_def->doi);
487 calipso[6] = (len - CALIPSO_HDR_LEN) / 4;
488 calipso[7] = secattr->attr.mls.lvl,
489 crc = ~crc_ccitt(0xffff, calipso, len);
490 calipso[8] = crc & 0xff;
491 calipso[9] = (crc >> 8) & 0xff;
495 /* Hop-by-hop hdr helper functions
499 * calipso_opt_update - Replaces socket's hop options with a new set
501 * @hop: new hop options
504 * Replaces @sk's hop options with @hop. @hop may be NULL to leave
505 * the socket with no hop options.
508 static int calipso_opt_update(struct sock *sk, struct ipv6_opt_hdr *hop)
510 struct ipv6_txoptions *old = txopt_get(inet6_sk(sk)), *txopts;
512 txopts = ipv6_renew_options_kern(sk, old, IPV6_HOPOPTS,
513 hop, hop ? ipv6_optlen(hop) : 0);
516 return PTR_ERR(txopts);
518 txopts = ipv6_update_options(sk, txopts);
520 atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
528 * calipso_tlv_len - Returns the length of the TLV
529 * @opt: the option header
530 * @offset: offset of the TLV within the header
533 * Returns the length of the TLV option at offset @offset within
534 * the option header @opt. Checks that the entire TLV fits inside
535 * the option header, returns a negative value if this is not the case.
537 static int calipso_tlv_len(struct ipv6_opt_hdr *opt, unsigned int offset)
539 unsigned char *tlv = (unsigned char *)opt;
540 unsigned int opt_len = ipv6_optlen(opt), tlv_len;
542 if (offset < sizeof(*opt) || offset >= opt_len)
544 if (tlv[offset] == IPV6_TLV_PAD1)
546 if (offset + 1 >= opt_len)
548 tlv_len = tlv[offset + 1] + 2;
549 if (offset + tlv_len > opt_len)
555 * calipso_opt_find - Finds the CALIPSO option in an IPv6 hop options header
556 * @hop: the hop options header
557 * @start: on return holds the offset of any leading padding
558 * @end: on return holds the offset of the first non-pad TLV after CALIPSO
561 * Finds the space occupied by a CALIPSO option (including any leading and
564 * If a CALIPSO option exists set @start and @end to the
565 * offsets within @hop of the start of padding before the first
566 * CALIPSO option and the end of padding after the first CALIPSO
567 * option. In this case the function returns 0.
569 * In the absence of a CALIPSO option, @start and @end will be
570 * set to the start and end of any trailing padding in the header.
571 * This is useful when appending a new option, as the caller may want
572 * to overwrite some of this padding. In this case the function will
575 static int calipso_opt_find(struct ipv6_opt_hdr *hop, unsigned int *start,
578 int ret_val = -ENOENT, tlv_len;
579 unsigned int opt_len, offset, offset_s = 0, offset_e = 0;
580 unsigned char *opt = (unsigned char *)hop;
582 opt_len = ipv6_optlen(hop);
583 offset = sizeof(*hop);
585 while (offset < opt_len) {
586 tlv_len = calipso_tlv_len(hop, offset);
590 switch (opt[offset]) {
596 case IPV6_TLV_CALIPSO:
611 *start = offset_s + calipso_tlv_len(hop, offset_s);
613 *start = sizeof(*hop);
615 *end = offset_e + calipso_tlv_len(hop, offset_e);
623 * calipso_opt_insert - Inserts a CALIPSO option into an IPv6 hop opt hdr
624 * @hop: the original hop options header
625 * @doi_def: the CALIPSO DOI to use
626 * @secattr: the specific security attributes of the socket
629 * Creates a new hop options header based on @hop with a
630 * CALIPSO option added to it. If @hop already contains a CALIPSO
631 * option this is overwritten, otherwise the new option is appended
632 * after any existing options. If @hop is NULL then the new header
633 * will contain just the CALIPSO option and any needed padding.
636 static struct ipv6_opt_hdr *
637 calipso_opt_insert(struct ipv6_opt_hdr *hop,
638 const struct calipso_doi *doi_def,
639 const struct netlbl_lsm_secattr *secattr)
641 unsigned int start, end, buf_len, pad, hop_len;
642 struct ipv6_opt_hdr *new;
646 hop_len = ipv6_optlen(hop);
647 ret_val = calipso_opt_find(hop, &start, &end);
648 if (ret_val && ret_val != -ENOENT)
649 return ERR_PTR(ret_val);
652 start = sizeof(*hop);
656 buf_len = hop_len + start - end + CALIPSO_OPT_LEN_MAX_WITH_PAD;
657 new = kzalloc(buf_len, GFP_ATOMIC);
659 return ERR_PTR(-ENOMEM);
661 if (start > sizeof(*hop))
662 memcpy(new, hop, start);
663 ret_val = calipso_genopt((unsigned char *)new, start, buf_len, doi_def,
666 return ERR_PTR(ret_val);
668 buf_len = start + ret_val;
669 /* At this point buf_len aligns to 4n, so (buf_len & 4) pads to 8n */
670 pad = ((buf_len & 4) + (end & 7)) & 7;
671 calipso_pad_write((unsigned char *)new, buf_len, pad);
674 if (end != hop_len) {
675 memcpy((char *)new + buf_len, (char *)hop + end, hop_len - end);
676 buf_len += hop_len - end;
679 new->hdrlen = buf_len / 8 - 1;
685 * calipso_opt_del - Removes the CALIPSO option from an option header
686 * @hop: the original header
687 * @new: the new header
690 * Creates a new header based on @hop without any CALIPSO option. If @hop
691 * doesn't contain a CALIPSO option it returns -ENOENT. If @hop contains
692 * no other non-padding options, it returns zero with @new set to NULL.
693 * Otherwise it returns zero, creates a new header without the CALIPSO
694 * option (and removing as much padding as possible) and returns with
695 * @new set to that header.
698 static int calipso_opt_del(struct ipv6_opt_hdr *hop,
699 struct ipv6_opt_hdr **new)
702 unsigned int start, end, delta, pad, hop_len;
704 ret_val = calipso_opt_find(hop, &start, &end);
708 hop_len = ipv6_optlen(hop);
709 if (start == sizeof(*hop) && end == hop_len) {
710 /* There's no other option in the header so return NULL */
715 delta = (end - start) & ~7;
716 *new = kzalloc(hop_len - delta, GFP_ATOMIC);
720 memcpy(*new, hop, start);
721 (*new)->hdrlen -= delta / 8;
722 pad = (end - start) & 7;
723 calipso_pad_write((unsigned char *)*new, start, pad);
725 memcpy((char *)*new + start + pad, (char *)hop + end,
732 * calipso_opt_getattr - Get the security attributes from a memory block
733 * @calipso: the CALIPSO option
734 * @secattr: the security attributes
737 * Inspect @calipso and return the security attributes in @secattr.
738 * Returns zero on success and negative values on failure.
741 static int calipso_opt_getattr(const unsigned char *calipso,
742 struct netlbl_lsm_secattr *secattr)
744 int ret_val = -ENOMSG;
745 u32 doi, len = calipso[1], cat_len = calipso[6] * 4;
746 struct calipso_doi *doi_def;
748 if (cat_len + 8 > len)
751 doi = get_unaligned_be32(calipso + 2);
753 doi_def = calipso_doi_search(doi);
757 secattr->attr.mls.lvl = calipso[7];
758 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
761 ret_val = calipso_map_cat_ntoh(doi_def,
766 netlbl_catmap_free(secattr->attr.mls.cat);
770 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
773 secattr->type = NETLBL_NLTYPE_CALIPSO;
784 * calipso_sock_getattr - Get the security attributes from a sock
786 * @secattr: the security attributes
789 * Query @sk to see if there is a CALIPSO option attached to the sock and if
790 * there is return the CALIPSO security attributes in @secattr. This function
791 * requires that @sk be locked, or privately held, but it does not do any
792 * locking itself. Returns zero on success and negative values on failure.
795 static int calipso_sock_getattr(struct sock *sk,
796 struct netlbl_lsm_secattr *secattr)
798 struct ipv6_opt_hdr *hop;
799 int opt_len, len, ret_val = -ENOMSG, offset;
801 struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
803 if (!txopts || !txopts->hopopt)
806 hop = txopts->hopopt;
807 opt = (unsigned char *)hop;
808 opt_len = ipv6_optlen(hop);
809 offset = sizeof(*hop);
810 while (offset < opt_len) {
811 len = calipso_tlv_len(hop, offset);
816 switch (opt[offset]) {
817 case IPV6_TLV_CALIPSO:
818 if (len < CALIPSO_HDR_LEN)
821 ret_val = calipso_opt_getattr(&opt[offset],
835 * calipso_sock_setattr - Add a CALIPSO option to a socket
837 * @doi_def: the CALIPSO DOI to use
838 * @secattr: the specific security attributes of the socket
841 * Set the CALIPSO option on the given socket using the DOI definition and
842 * security attributes passed to the function. This function requires
843 * exclusive access to @sk, which means it either needs to be in the
844 * process of being created or locked. Returns zero on success and negative
848 static int calipso_sock_setattr(struct sock *sk,
849 const struct calipso_doi *doi_def,
850 const struct netlbl_lsm_secattr *secattr)
853 struct ipv6_opt_hdr *old, *new;
854 struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
858 old = txopts->hopopt;
860 new = calipso_opt_insert(old, doi_def, secattr);
865 ret_val = calipso_opt_update(sk, new);
872 * calipso_sock_delattr - Delete the CALIPSO option from a socket
876 * Removes the CALIPSO option from a socket, if present.
879 static void calipso_sock_delattr(struct sock *sk)
881 struct ipv6_opt_hdr *new_hop;
882 struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
884 if (!txopts || !txopts->hopopt)
887 if (calipso_opt_del(txopts->hopopt, &new_hop))
890 calipso_opt_update(sk, new_hop);
897 /* request sock functions.
901 * calipso_req_setattr - Add a CALIPSO option to a connection request socket
902 * @req: the connection request socket
903 * @doi_def: the CALIPSO DOI to use
904 * @secattr: the specific security attributes of the socket
907 * Set the CALIPSO option on the given socket using the DOI definition and
908 * security attributes passed to the function. Returns zero on success and
909 * negative values on failure.
912 static int calipso_req_setattr(struct request_sock *req,
913 const struct calipso_doi *doi_def,
914 const struct netlbl_lsm_secattr *secattr)
916 struct ipv6_txoptions *txopts;
917 struct inet_request_sock *req_inet = inet_rsk(req);
918 struct ipv6_opt_hdr *old, *new;
919 struct sock *sk = sk_to_full_sk(req_to_sk(req));
921 if (req_inet->ipv6_opt && req_inet->ipv6_opt->hopopt)
922 old = req_inet->ipv6_opt->hopopt;
926 new = calipso_opt_insert(old, doi_def, secattr);
930 txopts = ipv6_renew_options_kern(sk, req_inet->ipv6_opt, IPV6_HOPOPTS,
931 new, new ? ipv6_optlen(new) : 0);
936 return PTR_ERR(txopts);
938 txopts = xchg(&req_inet->ipv6_opt, txopts);
940 atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
948 * calipso_req_delattr - Delete the CALIPSO option from a request socket
949 * @reg: the request socket
952 * Removes the CALIPSO option from a request socket, if present.
955 static void calipso_req_delattr(struct request_sock *req)
957 struct inet_request_sock *req_inet = inet_rsk(req);
958 struct ipv6_opt_hdr *new;
959 struct ipv6_txoptions *txopts;
960 struct sock *sk = sk_to_full_sk(req_to_sk(req));
962 if (!req_inet->ipv6_opt || !req_inet->ipv6_opt->hopopt)
965 if (calipso_opt_del(req_inet->ipv6_opt->hopopt, &new))
966 return; /* Nothing to do */
968 txopts = ipv6_renew_options_kern(sk, req_inet->ipv6_opt, IPV6_HOPOPTS,
969 new, new ? ipv6_optlen(new) : 0);
971 if (!IS_ERR(txopts)) {
972 txopts = xchg(&req_inet->ipv6_opt, txopts);
974 atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
985 * calipso_skbuff_optptr - Find the CALIPSO option in the packet
989 * Parse the packet's IP header looking for a CALIPSO option. Returns a pointer
990 * to the start of the CALIPSO option on success, NULL if one if not found.
993 static unsigned char *calipso_skbuff_optptr(const struct sk_buff *skb)
995 const struct ipv6hdr *ip6_hdr = ipv6_hdr(skb);
998 if (ip6_hdr->nexthdr != NEXTHDR_HOP)
1001 offset = ipv6_find_tlv(skb, sizeof(*ip6_hdr), IPV6_TLV_CALIPSO);
1003 return (unsigned char *)ip6_hdr + offset;
1009 * calipso_skbuff_setattr - Set the CALIPSO option on a packet
1011 * @doi_def: the CALIPSO DOI to use
1012 * @secattr: the security attributes
1015 * Set the CALIPSO option on the given packet based on the security attributes.
1016 * Returns a pointer to the IP header on success and NULL on failure.
1019 static int calipso_skbuff_setattr(struct sk_buff *skb,
1020 const struct calipso_doi *doi_def,
1021 const struct netlbl_lsm_secattr *secattr)
1024 struct ipv6hdr *ip6_hdr;
1025 struct ipv6_opt_hdr *hop;
1026 unsigned char buf[CALIPSO_MAX_BUFFER];
1027 int len_delta, new_end, pad;
1028 unsigned int start, end;
1030 ip6_hdr = ipv6_hdr(skb);
1031 if (ip6_hdr->nexthdr == NEXTHDR_HOP) {
1032 hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
1033 ret_val = calipso_opt_find(hop, &start, &end);
1034 if (ret_val && ret_val != -ENOENT)
1041 memset(buf, 0, sizeof(buf));
1042 ret_val = calipso_genopt(buf, start & 3, sizeof(buf), doi_def, secattr);
1046 new_end = start + ret_val;
1047 /* At this point new_end aligns to 4n, so (new_end & 4) pads to 8n */
1048 pad = ((new_end & 4) + (end & 7)) & 7;
1049 len_delta = new_end - (int)end + pad;
1050 ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
1056 skb_push(skb, len_delta);
1058 skb_pull(skb, -len_delta);
1059 memmove((char *)ip6_hdr - len_delta, ip6_hdr,
1060 sizeof(*ip6_hdr) + start);
1061 skb_reset_network_header(skb);
1062 ip6_hdr = ipv6_hdr(skb);
1065 hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
1067 struct ipv6_opt_hdr *new_hop = (struct ipv6_opt_hdr *)buf;
1069 new_hop->nexthdr = ip6_hdr->nexthdr;
1070 new_hop->hdrlen = len_delta / 8 - 1;
1071 ip6_hdr->nexthdr = NEXTHDR_HOP;
1073 hop->hdrlen += len_delta / 8;
1075 memcpy((char *)hop + start, buf + (start & 3), new_end - start);
1076 calipso_pad_write((unsigned char *)hop, new_end, pad);
1082 * calipso_skbuff_delattr - Delete any CALIPSO options from a packet
1086 * Removes any and all CALIPSO options from the given packet. Returns zero on
1087 * success, negative values on failure.
1090 static int calipso_skbuff_delattr(struct sk_buff *skb)
1093 struct ipv6hdr *ip6_hdr;
1094 struct ipv6_opt_hdr *old_hop;
1095 u32 old_hop_len, start = 0, end = 0, delta, size, pad;
1097 if (!calipso_skbuff_optptr(skb))
1100 /* since we are changing the packet we should make a copy */
1101 ret_val = skb_cow(skb, skb_headroom(skb));
1105 ip6_hdr = ipv6_hdr(skb);
1106 old_hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
1107 old_hop_len = ipv6_optlen(old_hop);
1109 ret_val = calipso_opt_find(old_hop, &start, &end);
1113 if (start == sizeof(*old_hop) && end == old_hop_len) {
1114 /* There's no other option in the header so we delete
1115 * the whole thing. */
1116 delta = old_hop_len;
1117 size = sizeof(*ip6_hdr);
1118 ip6_hdr->nexthdr = old_hop->nexthdr;
1120 delta = (end - start) & ~7;
1122 old_hop->hdrlen -= delta / 8;
1123 pad = (end - start) & 7;
1124 size = sizeof(*ip6_hdr) + start + pad;
1125 calipso_pad_write((unsigned char *)old_hop, start, pad);
1129 skb_pull(skb, delta);
1130 memmove((char *)ip6_hdr + delta, ip6_hdr, size);
1131 skb_reset_network_header(skb);
1137 static const struct netlbl_calipso_ops ops = {
1138 .doi_add = calipso_doi_add,
1139 .doi_free = calipso_doi_free,
1140 .doi_remove = calipso_doi_remove,
1141 .doi_getdef = calipso_doi_getdef,
1142 .doi_putdef = calipso_doi_putdef,
1143 .doi_walk = calipso_doi_walk,
1144 .sock_getattr = calipso_sock_getattr,
1145 .sock_setattr = calipso_sock_setattr,
1146 .sock_delattr = calipso_sock_delattr,
1147 .req_setattr = calipso_req_setattr,
1148 .req_delattr = calipso_req_delattr,
1149 .opt_getattr = calipso_opt_getattr,
1150 .skbuff_optptr = calipso_skbuff_optptr,
1151 .skbuff_setattr = calipso_skbuff_setattr,
1152 .skbuff_delattr = calipso_skbuff_delattr,
1156 * calipso_init - Initialize the CALIPSO module
1159 * Initialize the CALIPSO module and prepare it for use. Returns zero on
1160 * success and negative values on failure.
1163 int __init calipso_init(void)
1165 netlbl_calipso_ops_register(&ops);
1169 void calipso_exit(void)
1171 netlbl_calipso_ops_register(NULL);