Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/net/ipv6/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 7 kB image not shown  

Quelle  exthdrs_core.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * IPv6 library code, needed by static components when full IPv6 support is
 * not configured or static.
 */

#include <linux/export.h>
#include <net/ipv6.h>

/*
 * find out if nexthdr is a well-known extension header or a protocol
 */


bool ipv6_ext_hdr(u8 nexthdr)
{
 /*
 * find out if nexthdr is an extension header or a protocol
 */

 return   (nexthdr == NEXTHDR_HOP) ||
   (nexthdr == NEXTHDR_ROUTING) ||
   (nexthdr == NEXTHDR_FRAGMENT) ||
   (nexthdr == NEXTHDR_AUTH) ||
   (nexthdr == NEXTHDR_NONE) ||
   (nexthdr == NEXTHDR_DEST);
}
EXPORT_SYMBOL(ipv6_ext_hdr);

/*
 * Skip any extension headers. This is used by the ICMP module.
 *
 * Note that strictly speaking this conflicts with RFC 2460 4.0:
 * ...The contents and semantics of each extension header determine whether
 * or not to proceed to the next header.  Therefore, extension headers must
 * be processed strictly in the order they appear in the packet; a
 * receiver must not, for example, scan through a packet looking for a
 * particular kind of extension header and process that header prior to
 * processing all preceding ones.
 *
 * We do exactly this. This is a protocol bug. We can't decide after a
 * seeing an unknown discard-with-error flavour TLV option if it's a
 * ICMP error message or not (errors should never be send in reply to
 * ICMP error messages).
 *
 * But I see no other way to do this. This might need to be reexamined
 * when Linux implements ESP (and maybe AUTH) headers.
 * --AK
 *
 * This function parses (probably truncated) exthdr set "hdr".
 * "nexthdrp" initially points to some place,
 * where type of the first header can be found.
 *
 * It skips all well-known exthdrs, and returns pointer to the start
 * of unparsable area i.e. the first header with unknown type.
 * If it is not NULL *nexthdr is updated by type/protocol of this header.
 *
 * NOTES: - if packet terminated with NEXTHDR_NONE it returns NULL.
 *        - it may return pointer pointing beyond end of packet,
 *     if the last recognized header is truncated in the middle.
 *        - if packet is truncated, so that all parsed headers are skipped,
 *     it returns NULL.
 *   - First fragment header is skipped, not-first ones
 *     are considered as unparsable.
 *   - Reports the offset field of the final fragment header so it is
 *     possible to tell whether this is a first fragment, later fragment,
 *     or not fragmented.
 *   - ESP is unparsable for now and considered like
 *     normal payload protocol.
 *   - Note also special handling of AUTH header. Thanks to IPsec wizards.
 *
 * --ANK (980726)
 */


int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
       __be16 *frag_offp)
{
 u8 nexthdr = *nexthdrp;

 *frag_offp = 0;

 while (ipv6_ext_hdr(nexthdr)) {
  struct ipv6_opt_hdr _hdr, *hp;
  int hdrlen;

  if (nexthdr == NEXTHDR_NONE)
   return -1;
  hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
  if (!hp)
   return -1;
  if (nexthdr == NEXTHDR_FRAGMENT) {
   __be16 _frag_off, *fp;
   fp = skb_header_pointer(skb,
      start+offsetof(struct frag_hdr,
              frag_off),
      sizeof(_frag_off),
      &_frag_off);
   if (!fp)
    return -1;

   *frag_offp = *fp;
   if (ntohs(*frag_offp) & ~0x7)
    break;
   hdrlen = 8;
  } else if (nexthdr == NEXTHDR_AUTH)
   hdrlen = ipv6_authlen(hp);
  else
   hdrlen = ipv6_optlen(hp);

  nexthdr = hp->nexthdr;
  start += hdrlen;
 }

 *nexthdrp = nexthdr;
 return start;
}
EXPORT_SYMBOL(ipv6_skip_exthdr);

int ipv6_find_tlv(const struct sk_buff *skb, int offset, int type)
{
 const unsigned char *nh = skb_network_header(skb);
 int packet_len = skb_tail_pointer(skb) - skb_network_header(skb);
 struct ipv6_opt_hdr *hdr;
 int len;

 if (offset + 2 > packet_len)
  goto bad;
 hdr = (struct ipv6_opt_hdr *)(nh + offset);
 len = ((hdr->hdrlen + 1) << 3);

 if (offset + len > packet_len)
  goto bad;

 offset += 2;
 len -= 2;

 while (len > 0) {
  int opttype = nh[offset];
  int optlen;

  if (opttype == type)
   return offset;

  switch (opttype) {
  case IPV6_TLV_PAD1:
   optlen = 1;
   break;
  default:
   if (len < 2)
    goto bad;
   optlen = nh[offset + 1] + 2;
   if (optlen > len)
    goto bad;
   break;
  }
  offset += optlen;
  len -= optlen;
 }
 /* not_found */
 bad:
 return -1;
}
EXPORT_SYMBOL_GPL(ipv6_find_tlv);

/*
 * find the offset to specified header or the protocol number of last header
 * if target < 0. "last header" is transport protocol header, ESP, or
 * "No next header".
 *
 * Note that *offset is used as input/output parameter, and if it is not zero,
 * then it must be a valid offset to an inner IPv6 header. This can be used
 * to explore inner IPv6 header, eg. ICMPv6 error messages.
 *
 * If target header is found, its offset is set in *offset and return protocol
 * number. Otherwise, return -1.
 *
 * If the first fragment doesn't contain the final protocol header or
 * NEXTHDR_NONE it is considered invalid.
 *
 * Note that non-1st fragment is special case that "the protocol number
 * of last header" is "next header" field in Fragment header. In this case,
 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
 * isn't NULL.
 *
 * if flags is not NULL and it's a fragment, then the frag flag
 * IP6_FH_F_FRAG will be set. If it's an AH header, the
 * IP6_FH_F_AUTH flag is set and target < 0, then this function will
 * stop at the AH header. If IP6_FH_F_SKIP_RH flag was passed, then this
 * function will skip all those routing headers, where segements_left was 0.
 */

int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
    int target, unsigned short *fragoff, int *flags)
{
 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
 bool found;

 if (fragoff)
  *fragoff = 0;

 if (*offset) {
  struct ipv6hdr _ip6, *ip6;

  ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6);
  if (!ip6 || (ip6->version != 6))
   return -EBADMSG;
  start = *offset + sizeof(struct ipv6hdr);
  nexthdr = ip6->nexthdr;
 }

 do {
  struct ipv6_opt_hdr _hdr, *hp;
  unsigned int hdrlen;
  found = (nexthdr == target);

  if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
   if (target < 0 || found)
    break;
   return -ENOENT;
  }

  hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
  if (!hp)
   return -EBADMSG;

  if (nexthdr == NEXTHDR_ROUTING) {
   struct ipv6_rt_hdr _rh, *rh;

   rh = skb_header_pointer(skb, start, sizeof(_rh),
      &_rh);
   if (!rh)
    return -EBADMSG;

   if (flags && (*flags & IP6_FH_F_SKIP_RH) &&
       rh->segments_left == 0)
    found = false;
  }

  if (nexthdr == NEXTHDR_FRAGMENT) {
   unsigned short _frag_off;
   __be16 *fp;

   if (flags) /* Indicate that this is a fragment */
    *flags |= IP6_FH_F_FRAG;
   fp = skb_header_pointer(skb,
      start+offsetof(struct frag_hdr,
              frag_off),
      sizeof(_frag_off),
      &_frag_off);
   if (!fp)
    return -EBADMSG;

   _frag_off = ntohs(*fp) & ~0x7;
   if (_frag_off) {
    if (target < 0 &&
        ((!ipv6_ext_hdr(hp->nexthdr)) ||
         hp->nexthdr == NEXTHDR_NONE)) {
     if (fragoff)
      *fragoff = _frag_off;
     return hp->nexthdr;
    }
    if (!found)
     return -ENOENT;
    if (fragoff)
     *fragoff = _frag_off;
    break;
   }
   hdrlen = 8;
  } else if (nexthdr == NEXTHDR_AUTH) {
   if (flags && (*flags & IP6_FH_F_AUTH) && (target < 0))
    break;
   hdrlen = ipv6_authlen(hp);
  } else
   hdrlen = ipv6_optlen(hp);

  if (!found) {
   nexthdr = hp->nexthdr;
   start += hdrlen;
  }
 } while (!found);

 *offset = start;
 return nexthdr;
}
EXPORT_SYMBOL(ipv6_find_hdr);

Messung V0.5
C=97 H=91 G=93

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.