]>
git.saurik.com Git - apple/xnu.git/blob - bsd/net/classq/classq_util.c
   2  * Copyright (c) 2007-2011 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  30  * Copyright (c) 1991-1997 Regents of the University of California. 
  31  * All rights reserved. 
  33  * Redistribution and use in source and binary forms, with or without 
  34  * modification, are permitted provided that the following conditions 
  36  * 1. Redistributions of source code must retain the above copyright 
  37  *    notice, this list of conditions and the following disclaimer. 
  38  * 2. Redistributions in binary form must reproduce the above copyright 
  39  *    notice, this list of conditions and the following disclaimer in the 
  40  *    documentation and/or other materials provided with the distribution. 
  41  * 3. All advertising materials mentioning features or use of this software 
  42  *    must display the following acknowledgement: 
  43  *      This product includes software developed by the Network Research 
  44  *      Group at Lawrence Berkeley Laboratory. 
  45  * 4. Neither the name of the University nor of the Laboratory may be used 
  46  *    to endorse or promote products derived from this software without 
  47  *    specific prior written permission. 
  49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 
  50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 
  53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  62 #include <sys/cdefs.h> 
  63 #include <sys/param.h> 
  65 #include <sys/errno.h> 
  66 #include <sys/random.h> 
  67 #include <sys/kernel_types.h> 
  68 #include <sys/sysctl.h> 
  71 #include <net/net_osdep.h> 
  72 #include <net/classq/classq.h> 
  74 #include <netinet/in.h> 
  75 #include <netinet/in_systm.h> 
  76 #include <netinet/ip.h> 
  78 #include <netinet/ip6.h> 
  80 #include <netinet/tcp.h> 
  81 #include <netinet/udp.h> 
  83 #include <libkern/libkern.h> 
  87  * read and write diffserv field in IPv4 or IPv6 header 
  90 read_dsfield(struct mbuf 
*m
, struct pf_mtag 
*t
) 
  93         u_int8_t ds_field 
= 0; 
  95         if (t
->pftag_hdr 
== NULL 
|| 
  96             !(t
->pftag_flags 
& (PF_TAG_HDR_INET 
| PF_TAG_HDR_INET6
))) { 
 100         /* verify that hdr is within the mbuf data */ 
 101         for (m0 
= m
; m0 
!= NULL
; m0 
= m0
->m_next
) { 
 102                 if (((caddr_t
)t
->pftag_hdr 
>= m0
->m_data
) && 
 103                     ((caddr_t
)t
->pftag_hdr 
< m0
->m_data 
+ m0
->m_len
)) { 
 108                 /* ick, tag info is stale */ 
 109                 printf("%s: can't locate header!\n", __func__
); 
 113         if (t
->pftag_flags 
& PF_TAG_HDR_INET
) { 
 114                 struct ip 
*ip 
= (struct ip 
*)(void *)t
->pftag_hdr
; 
 116                 if (((uintptr_t)ip 
+ sizeof(*ip
)) > 
 117                     ((uintptr_t)mbuf_datastart(m0
) + mbuf_maxlen(m0
))) { 
 118                         return 0;             /* out of bounds */ 
 121                         return (u_int8_t
)0;   /* version mismatch! */ 
 123                 ds_field 
= ip
->ip_tos
; 
 126         else if (t
->pftag_flags 
& PF_TAG_HDR_INET6
) { 
 127                 struct ip6_hdr 
*ip6 
= (struct ip6_hdr 
*)(void *)t
->pftag_hdr
; 
 130                 if (((uintptr_t)ip6 
+ sizeof(*ip6
)) > 
 131                     ((uintptr_t)mbuf_datastart(m0
) + mbuf_maxlen(m0
))) { 
 132                         return 0;             /* out of bounds */ 
 134                 flowlabel 
= ntohl(ip6
->ip6_flow
); 
 135                 if ((flowlabel 
>> 28) != 6) { 
 136                         return (u_int8_t
)0;   /* version mismatch! */ 
 138                 ds_field 
= (flowlabel 
>> 20) & 0xff; 
 145 write_dsfield(struct mbuf 
*m
, struct pf_mtag 
*t
, u_int8_t dsfield
) 
 149         if (t
->pftag_hdr 
== NULL 
|| 
 150             !(t
->pftag_flags 
& (PF_TAG_HDR_INET 
| PF_TAG_HDR_INET6
))) { 
 154         /* verify that hdr is within the mbuf data */ 
 155         for (m0 
= m
; m0 
!= NULL
; m0 
= m0
->m_next
) { 
 156                 if (((caddr_t
)t
->pftag_hdr 
>= m0
->m_data
) && 
 157                     ((caddr_t
)t
->pftag_hdr 
< m0
->m_data 
+ m0
->m_len
)) { 
 162                 /* ick, tag info is stale */ 
 163                 printf("%s: can't locate header!\n", __func__
); 
 167         if (t
->pftag_flags 
& PF_TAG_HDR_INET
) { 
 168                 struct ip 
*ip 
= (struct ip 
*)(void *)t
->pftag_hdr
; 
 172                 if (((uintptr_t)ip 
+ sizeof(*ip
)) > 
 173                     ((uintptr_t)mbuf_datastart(m0
) + mbuf_maxlen(m0
))) { 
 174                         return;         /* out of bounds */ 
 177                         return;         /* version mismatch! */ 
 180                 dsfield 
|= old 
& 3;     /* leave CU bits */ 
 181                 if (old 
== dsfield
) { 
 184                 ip
->ip_tos 
= dsfield
; 
 186                  * update checksum (from RFC1624) 
 187                  *         HC' = ~(~HC + ~m + m') 
 189                 sum 
= ~ntohs(ip
->ip_sum
) & 0xffff; 
 190                 sum 
+= 0xff00 + (~old 
& 0xff) + dsfield
; 
 191                 sum 
= (sum 
>> 16) + (sum 
& 0xffff); 
 192                 sum 
+= (sum 
>> 16);  /* add carry */ 
 194                 ip
->ip_sum 
= htons(~sum 
& 0xffff); 
 197         else if (t
->pftag_flags 
& PF_TAG_HDR_INET6
) { 
 198                 struct ip6_hdr 
*ip6 
= (struct ip6_hdr 
*)t
->pftag_hdr
; 
 201                 if (((uintptr_t)ip6 
+ sizeof(*ip6
)) > 
 202                     ((uintptr_t)mbuf_datastart(m0
) + mbuf_maxlen(m0
))) { 
 203                         return;         /* out of bounds */ 
 205                 flowlabel 
= ntohl(ip6
->ip6_flow
); 
 206                 if ((flowlabel 
>> 28) != 6) { 
 207                         return;         /* version mismatch! */ 
 209                 flowlabel 
= (flowlabel 
& 0xf03fffff) | (dsfield 
<< 20); 
 210                 ip6
->ip6_flow 
= htonl(flowlabel
); 
 216  * try to mark CE bit to the packet. 
 217  *    returns 1 if successfully marked, 0 otherwise. 
 220 mark_ecn(struct mbuf 
*m
, struct pf_mtag 
*t
, int flags
) 
 226         if ((hdr 
= t
->pftag_hdr
) == NULL 
|| 
 227             !(t
->pftag_flags 
& (PF_TAG_HDR_INET 
| PF_TAG_HDR_INET6
))) { 
 231         /* verify that hdr is within the mbuf data */ 
 232         for (m0 
= m
; m0 
!= NULL
; m0 
= m0
->m_next
) { 
 233                 if (((caddr_t
)hdr 
>= m0
->m_data
) && 
 234                     ((caddr_t
)hdr 
< m0
->m_data 
+ m0
->m_len
)) { 
 239                 /* ick, tag info is stale */ 
 240                 printf("%s: can't locate header!\n", __func__
); 
 244         if (t
->pftag_flags 
& PF_TAG_HDR_INET
) { 
 246         } else if (t
->pftag_flags 
& PF_TAG_HDR_INET6
) { 
 254                 if (flags 
& CLASSQF_ECN4
) {     /* REDF_ECN4 == BLUEF_ECN4 */ 
 259                         if (((uintptr_t)ip 
+ sizeof(*ip
)) > 
 260                             ((uintptr_t)mbuf_datastart(m0
) + mbuf_maxlen(m0
))) { 
 261                                 return 0;     /* out of bounds */ 
 264                                 return 0;     /* version mismatch! */ 
 266                         if ((ip
->ip_tos 
& IPTOS_ECN_MASK
) == IPTOS_ECN_NOTECT
) { 
 267                                 return 0;     /* not-ECT */ 
 269                         if ((ip
->ip_tos 
& IPTOS_ECN_MASK
) == IPTOS_ECN_CE
) { 
 270                                 return 1;     /* already marked */ 
 273                          * ecn-capable but not marked, 
 274                          * mark CE and update checksum 
 277                         ip
->ip_tos 
|= IPTOS_ECN_CE
; 
 279                          * update checksum (from RFC1624) only if hw 
 280                          * checksum is not supported. 
 281                          *         HC' = ~(~HC + ~m + m') 
 283                         if (!(m
->m_pkthdr
.csum_flags 
& CSUM_DELAY_IP
)) { 
 284                                 sum 
= ~ntohs(ip
->ip_sum
) & 0xffff; 
 285                                 sum 
+= (~otos 
& 0xffff) + ip
->ip_tos
; 
 286                                 sum 
= (sum 
>> 16) + (sum 
& 0xffff); 
 287                                 sum 
+= (sum 
>> 16);  /* add carry */ 
 288                                 ip
->ip_sum 
= htons(~sum 
& 0xffff); 
 295                 if (flags 
& CLASSQF_ECN6
) {     /* REDF_ECN6 == BLUEF_ECN6 */ 
 296                         struct ip6_hdr 
*ip6 
= hdr
; 
 299                         if (((uintptr_t)ip6 
+ sizeof(*ip6
)) > 
 300                             ((uintptr_t)mbuf_datastart(m0
) + mbuf_maxlen(m0
))) { 
 301                                 return 0;     /* out of bounds */ 
 303                         flowlabel 
= ntohl(ip6
->ip6_flow
); 
 304                         if ((flowlabel 
>> 28) != 6) { 
 305                                 return 0;     /* version mismatch! */ 
 307                         if ((flowlabel 
& (IPTOS_ECN_MASK 
<< 20)) == 
 308                             (IPTOS_ECN_NOTECT 
<< 20)) { 
 309                                 return 0;     /* not-ECT */ 
 311                         if ((flowlabel 
& (IPTOS_ECN_MASK 
<< 20)) == 
 312                             (IPTOS_ECN_CE 
<< 20)) { 
 313                                 return 1;     /* already marked */ 
 316                          * ecn-capable but not marked,  mark CE 
 318                         flowlabel 
|= (IPTOS_ECN_CE 
<< 20); 
 319                         ip6
->ip6_flow 
= htonl(flowlabel
);