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 void ipv6_rpl_srh_decompress(struct ipv6_rpl_sr_hdr
*outhdr
,
33 const struct ipv6_rpl_sr_hdr
*inhdr
,
34 const struct in6_addr
*daddr
, unsigned char n
)
38 outhdr
->nexthdr
= inhdr
->nexthdr
;
39 outhdr
->hdrlen
= (((n
+ 1) * sizeof(struct in6_addr
)) >> 3);
41 outhdr
->type
= inhdr
->type
;
42 outhdr
->segments_left
= inhdr
->segments_left
;
46 for (i
= 0; i
< n
; i
++)
47 ipv6_rpl_addr_decompress(&outhdr
->rpl_segaddr
[i
], daddr
,
48 ipv6_rpl_segdata_pos(inhdr
, i
),
51 ipv6_rpl_addr_decompress(&outhdr
->rpl_segaddr
[n
], daddr
,
52 ipv6_rpl_segdata_pos(inhdr
, n
),
56 static unsigned char ipv6_rpl_srh_calc_cmpri(const struct ipv6_rpl_sr_hdr
*inhdr
,
57 const struct in6_addr
*daddr
,
63 for (plen
= 0; plen
< sizeof(*daddr
); plen
++) {
64 for (i
= 0; i
< n
; i
++) {
65 if (daddr
->s6_addr
[plen
] !=
66 inhdr
->rpl_segaddr
[i
].s6_addr
[plen
])
71 return IPV6_RPL_BEST_ADDR_COMPRESSION
;
74 static unsigned char ipv6_rpl_srh_calc_cmpre(const struct in6_addr
*daddr
,
75 const struct in6_addr
*last_segment
)
79 for (plen
= 0; plen
< sizeof(*daddr
); plen
++) {
80 if (daddr
->s6_addr
[plen
] != last_segment
->s6_addr
[plen
])
84 return IPV6_RPL_BEST_ADDR_COMPRESSION
;
87 void ipv6_rpl_srh_compress(struct ipv6_rpl_sr_hdr
*outhdr
,
88 const struct ipv6_rpl_sr_hdr
*inhdr
,
89 const struct in6_addr
*daddr
, unsigned char n
)
91 unsigned char cmpri
, cmpre
;
95 cmpri
= ipv6_rpl_srh_calc_cmpri(inhdr
, daddr
, n
);
96 cmpre
= ipv6_rpl_srh_calc_cmpre(daddr
, &inhdr
->rpl_segaddr
[n
]);
98 outhdr
->nexthdr
= inhdr
->nexthdr
;
99 seglen
= (n
* IPV6_PFXTAIL_LEN(cmpri
)) + IPV6_PFXTAIL_LEN(cmpre
);
100 outhdr
->hdrlen
= seglen
>> 3;
103 outhdr
->pad
= 8 - (seglen
& 0x7);
107 outhdr
->type
= inhdr
->type
;
108 outhdr
->segments_left
= inhdr
->segments_left
;
109 outhdr
->cmpri
= cmpri
;
110 outhdr
->cmpre
= cmpre
;
112 for (i
= 0; i
< n
; i
++)
113 ipv6_rpl_addr_compress(ipv6_rpl_segdata_pos(outhdr
, i
),
114 &inhdr
->rpl_segaddr
[i
], cmpri
);
116 ipv6_rpl_addr_compress(ipv6_rpl_segdata_pos(outhdr
, n
),
117 &inhdr
->rpl_segaddr
[n
], cmpre
);