1 // SPDX-License-Identifier: GPL-2.0-only
4 * (C) 2020 Alexander Aring <alex.aring@gmail.com>
10 #define IPV6_PFXTAIL_LEN(x) (sizeof(struct in6_addr) - (x))
11 #define IPV6_RPL_BEST_ADDR_COMPRESSION 15
13 static void ipv6_rpl_addr_decompress(struct in6_addr
*dst
,
14 const struct in6_addr
*daddr
,
15 const void *post
, unsigned char pfx
)
17 memcpy(dst
, daddr
, pfx
);
18 memcpy(&dst
->s6_addr
[pfx
], post
, IPV6_PFXTAIL_LEN(pfx
));
21 static void ipv6_rpl_addr_compress(void *dst
, const struct in6_addr
*addr
,
24 memcpy(dst
, &addr
->s6_addr
[pfx
], IPV6_PFXTAIL_LEN(pfx
));
27 static void *ipv6_rpl_segdata_pos(const struct ipv6_rpl_sr_hdr
*hdr
, int i
)
29 return (void *)&hdr
->rpl_segdata
[i
* IPV6_PFXTAIL_LEN(hdr
->cmpri
)];
32 size_t ipv6_rpl_srh_size(unsigned char n
, unsigned char cmpri
,
35 return (n
* IPV6_PFXTAIL_LEN(cmpri
)) + IPV6_PFXTAIL_LEN(cmpre
);
38 void ipv6_rpl_srh_decompress(struct ipv6_rpl_sr_hdr
*outhdr
,
39 const struct ipv6_rpl_sr_hdr
*inhdr
,
40 const struct in6_addr
*daddr
, unsigned char n
)
44 outhdr
->nexthdr
= inhdr
->nexthdr
;
45 outhdr
->hdrlen
= (((n
+ 1) * sizeof(struct in6_addr
)) >> 3);
47 outhdr
->type
= inhdr
->type
;
48 outhdr
->segments_left
= inhdr
->segments_left
;
52 for (i
= 0; i
< n
; i
++)
53 ipv6_rpl_addr_decompress(&outhdr
->rpl_segaddr
[i
], daddr
,
54 ipv6_rpl_segdata_pos(inhdr
, i
),
57 ipv6_rpl_addr_decompress(&outhdr
->rpl_segaddr
[n
], daddr
,
58 ipv6_rpl_segdata_pos(inhdr
, n
),
62 static unsigned char ipv6_rpl_srh_calc_cmpri(const struct ipv6_rpl_sr_hdr
*inhdr
,
63 const struct in6_addr
*daddr
,
69 for (plen
= 0; plen
< sizeof(*daddr
); plen
++) {
70 for (i
= 0; i
< n
; i
++) {
71 if (daddr
->s6_addr
[plen
] !=
72 inhdr
->rpl_segaddr
[i
].s6_addr
[plen
])
77 return IPV6_RPL_BEST_ADDR_COMPRESSION
;
80 static unsigned char ipv6_rpl_srh_calc_cmpre(const struct in6_addr
*daddr
,
81 const struct in6_addr
*last_segment
)
85 for (plen
= 0; plen
< sizeof(*daddr
); plen
++) {
86 if (daddr
->s6_addr
[plen
] != last_segment
->s6_addr
[plen
])
90 return IPV6_RPL_BEST_ADDR_COMPRESSION
;
93 void ipv6_rpl_srh_compress(struct ipv6_rpl_sr_hdr
*outhdr
,
94 const struct ipv6_rpl_sr_hdr
*inhdr
,
95 const struct in6_addr
*daddr
, unsigned char n
)
97 unsigned char cmpri
, cmpre
;
101 cmpri
= ipv6_rpl_srh_calc_cmpri(inhdr
, daddr
, n
);
102 cmpre
= ipv6_rpl_srh_calc_cmpre(daddr
, &inhdr
->rpl_segaddr
[n
]);
104 outhdr
->nexthdr
= inhdr
->nexthdr
;
105 seglen
= (n
* IPV6_PFXTAIL_LEN(cmpri
)) + IPV6_PFXTAIL_LEN(cmpre
);
106 outhdr
->hdrlen
= seglen
>> 3;
109 outhdr
->pad
= 8 - (seglen
& 0x7);
113 outhdr
->type
= inhdr
->type
;
114 outhdr
->segments_left
= inhdr
->segments_left
;
115 outhdr
->cmpri
= cmpri
;
116 outhdr
->cmpre
= cmpre
;
118 for (i
= 0; i
< n
; i
++)
119 ipv6_rpl_addr_compress(ipv6_rpl_segdata_pos(outhdr
, i
),
120 &inhdr
->rpl_segaddr
[i
], cmpri
);
122 ipv6_rpl_addr_compress(ipv6_rpl_segdata_pos(outhdr
, n
),
123 &inhdr
->rpl_segaddr
[n
], cmpre
);