^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Authors:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * (C) 2020 Alexander Aring <alex.aring@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <net/ipv6.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <net/rpl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #define IPV6_PFXTAIL_LEN(x) (sizeof(struct in6_addr) - (x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #define IPV6_RPL_BEST_ADDR_COMPRESSION 15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static void ipv6_rpl_addr_decompress(struct in6_addr *dst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) const struct in6_addr *daddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) const void *post, unsigned char pfx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) memcpy(dst, daddr, pfx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) memcpy(&dst->s6_addr[pfx], post, IPV6_PFXTAIL_LEN(pfx));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static void ipv6_rpl_addr_compress(void *dst, const struct in6_addr *addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) unsigned char pfx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) memcpy(dst, &addr->s6_addr[pfx], IPV6_PFXTAIL_LEN(pfx));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static void *ipv6_rpl_segdata_pos(const struct ipv6_rpl_sr_hdr *hdr, int i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return (void *)&hdr->rpl_segdata[i * IPV6_PFXTAIL_LEN(hdr->cmpri)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) size_t ipv6_rpl_srh_size(unsigned char n, unsigned char cmpri,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned char cmpre)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return (n * IPV6_PFXTAIL_LEN(cmpri)) + IPV6_PFXTAIL_LEN(cmpre);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) void ipv6_rpl_srh_decompress(struct ipv6_rpl_sr_hdr *outhdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) const struct ipv6_rpl_sr_hdr *inhdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) const struct in6_addr *daddr, unsigned char n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) outhdr->nexthdr = inhdr->nexthdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) outhdr->hdrlen = (((n + 1) * sizeof(struct in6_addr)) >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) outhdr->pad = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) outhdr->type = inhdr->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) outhdr->segments_left = inhdr->segments_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) outhdr->cmpri = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) outhdr->cmpre = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) for (i = 0; i < n; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) ipv6_rpl_addr_decompress(&outhdr->rpl_segaddr[i], daddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) ipv6_rpl_segdata_pos(inhdr, i),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) inhdr->cmpri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) ipv6_rpl_addr_decompress(&outhdr->rpl_segaddr[n], daddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) ipv6_rpl_segdata_pos(inhdr, n),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) inhdr->cmpre);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static unsigned char ipv6_rpl_srh_calc_cmpri(const struct ipv6_rpl_sr_hdr *inhdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) const struct in6_addr *daddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) unsigned char n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) unsigned char plen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) for (plen = 0; plen < sizeof(*daddr); plen++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) for (i = 0; i < n; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (daddr->s6_addr[plen] !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) inhdr->rpl_segaddr[i].s6_addr[plen])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return plen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return IPV6_RPL_BEST_ADDR_COMPRESSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static unsigned char ipv6_rpl_srh_calc_cmpre(const struct in6_addr *daddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) const struct in6_addr *last_segment)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) unsigned int plen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) for (plen = 0; plen < sizeof(*daddr); plen++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (daddr->s6_addr[plen] != last_segment->s6_addr[plen])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return plen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return IPV6_RPL_BEST_ADDR_COMPRESSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) void ipv6_rpl_srh_compress(struct ipv6_rpl_sr_hdr *outhdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) const struct ipv6_rpl_sr_hdr *inhdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) const struct in6_addr *daddr, unsigned char n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) unsigned char cmpri, cmpre;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) size_t seglen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) cmpri = ipv6_rpl_srh_calc_cmpri(inhdr, daddr, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) cmpre = ipv6_rpl_srh_calc_cmpre(daddr, &inhdr->rpl_segaddr[n]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) outhdr->nexthdr = inhdr->nexthdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) seglen = (n * IPV6_PFXTAIL_LEN(cmpri)) + IPV6_PFXTAIL_LEN(cmpre);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) outhdr->hdrlen = seglen >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (seglen & 0x7) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) outhdr->hdrlen++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) outhdr->pad = 8 - (seglen & 0x7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) outhdr->pad = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) outhdr->type = inhdr->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) outhdr->segments_left = inhdr->segments_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) outhdr->cmpri = cmpri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) outhdr->cmpre = cmpre;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) for (i = 0; i < n; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) ipv6_rpl_addr_compress(ipv6_rpl_segdata_pos(outhdr, i),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) &inhdr->rpl_segaddr[i], cmpri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) ipv6_rpl_addr_compress(ipv6_rpl_segdata_pos(outhdr, n),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) &inhdr->rpl_segaddr[n], cmpre);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }