blob: 39573e490a661854cb525e63ad7b573080012e04 [file] [log] [blame]
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +03001/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * Copyright (C) 2013 Allied Telesis Labs NZ
4 * Chris Packham, <judge.packham@gmail.com>
5 *
6 * Copyright (C) 2022 YADRO
7 * Viacheslav Mitrofanov <v.v.mitrofanov@yadro.com>
8 */
9
10#ifndef __NET6_H__
11#define __NET6_H__
12
13#include <net.h>
Simon Glassa86ea1c2025-05-15 17:31:47 -060014#include <asm/byteorder.h>
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +030015#include <linux/ctype.h>
Tom Rinia4a8ea92023-12-14 13:16:57 -050016#include <linux/errno.h>
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +030017
18/* struct in6_addr - 128 bits long IPv6 address */
19struct in6_addr {
20 union {
21 u8 u6_addr8[16];
22 __be16 u6_addr16[8];
23 __be32 u6_addr32[4];
24 } in6_u;
25
26#define s6_addr in6_u.u6_addr8
27#define s6_addr16 in6_u.u6_addr16
28#define s6_addr32 in6_u.u6_addr32
Sergei Antonovdc4d9c22023-01-18 20:52:18 +030029} __packed;
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +030030
31#define IN6ADDRSZ sizeof(struct in6_addr)
32#define INETHADDRSZ sizeof(net_ethaddr)
33
34#define PROT_IP6 0x86DD /* IPv6 protocol */
35#define PROT_ICMPV6 58 /* ICMPv6 protocol*/
36
37#define IPV6_ADDRSCOPE_INTF 0x01
38#define IPV6_ADDRSCOPE_LINK 0x02
39#define IPV6_ADDRSCOPE_AMDIN 0x04
40#define IPV6_ADDRSCOPE_SITE 0x05
41#define IPV6_ADDRSCOPE_ORG 0x08
42#define IPV6_ADDRSCOPE_GLOBAL 0x0E
43
44#define USE_IP6_CMD_PARAM "-ipv6"
45
46/**
47 * struct ipv6hdr - Internet Protocol V6 (IPv6) header.
48 *
49 * IPv6 packet header as defined in RFC 2460.
50 */
51struct ip6_hdr {
52#if defined(__LITTLE_ENDIAN_BITFIELD)
53 u8 priority:4,
54 version:4;
55#elif defined(__BIG_ENDIAN_BITFIELD)
56 u8 version:4,
57 priority:4;
58#else
59#error "Please fix <asm/byteorder.h>"
60#endif
61 u8 flow_lbl[3];
62 __be16 payload_len;
63 u8 nexthdr;
64 u8 hop_limit;
65 struct in6_addr saddr;
66 struct in6_addr daddr;
Sergei Antonovdc4d9c22023-01-18 20:52:18 +030067} __packed;
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +030068#define IP6_HDR_SIZE (sizeof(struct ip6_hdr))
69
70/* struct udp_hdr - User Datagram Protocol header */
71struct udp_hdr {
72 u16 udp_src; /* UDP source port */
73 u16 udp_dst; /* UDP destination port */
74 u16 udp_len; /* Length of UDP packet */
75 u16 udp_xsum; /* Checksum */
76} __packed;
77
78/*
79 * Handy for static initialisations of struct in6_addr, atlhough the
80 * c99 '= { 0 }' idiom might work depending on you compiler.
81 */
82#define ZERO_IPV6_ADDR { { { 0x00, 0x00, 0x00, 0x00, \
83 0x00, 0x00, 0x00, 0x00, \
84 0x00, 0x00, 0x00, 0x00, \
85 0x00, 0x00, 0x00, 0x00 } } }
Ehsan Mohandesia0d6d272023-04-21 17:08:21 -070086/*
87 * All-routers multicast address is the link-local scope address to reach all
88 * routers.
89 */
90#define ALL_ROUTERS_MULT_ADDR { { { 0xFF, 0x02, 0x00, 0x00, \
91 0x00, 0x00, 0x00, 0x00, \
92 0x00, 0x00, 0x00, 0x00, \
93 0x00, 0x00, 0x00, 0x02 } } }
Sean Edmond380ea552025-03-24 13:48:45 -070094/*
95 * With IPv6, the broadcast MAC address is not used. Instead, it should use
96 * the multicast address (see RFC RFC2464 section 7)
97 */
98#define IPV6_ALL_NODE_ETH_ADDR(_ip6_addr) {0x33, \
99 0x33, \
100 _ip6_addr.in6_u.u6_addr8[12], \
101 _ip6_addr.in6_u.u6_addr8[13], \
102 _ip6_addr.in6_u.u6_addr8[14], \
103 _ip6_addr.in6_u.u6_addr8[15]}
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300104
105#define IPV6_LINK_LOCAL_PREFIX 0xfe80
Ehsan Mohandesia0d6d272023-04-21 17:08:21 -0700106#define IPV6_LINK_LOCAL_MASK 0xffb0 /* The first 10-bit of address mask. */
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300107
108/* hop limit for neighbour discovery packets */
109#define IPV6_NDISC_HOPLIMIT 255
110#define NDISC_TIMEOUT 5000UL
111#define NDISC_TIMEOUT_COUNT 3
112
113/* struct icmp6hdr - Internet Control Message Protocol header for IPV6 */
114struct icmp6hdr {
115 u8 icmp6_type;
116#define IPV6_ICMP_ECHO_REQUEST 128
117#define IPV6_ICMP_ECHO_REPLY 129
118#define IPV6_NDISC_ROUTER_SOLICITATION 133
119#define IPV6_NDISC_ROUTER_ADVERTISEMENT 134
120#define IPV6_NDISC_NEIGHBOUR_SOLICITATION 135
121#define IPV6_NDISC_NEIGHBOUR_ADVERTISEMENT 136
122#define IPV6_NDISC_REDIRECT 137
123 u8 icmp6_code;
124 __be16 icmp6_cksum;
125
126 /* ICMPv6 data */
127 union {
128 __be32 un_data32[1];
129 __be16 un_data16[2];
130 u8 un_data8[4];
131
132 /* struct icmpv6_echo - echo request/reply message format */
133 struct icmpv6_echo {
134 __be16 identifier;
135 __be16 sequence;
136 } u_echo;
137
138 /* struct icmpv6_nd_advt - Neighbor Advertisement format */
139 struct icmpv6_nd_advt {
140#if defined(__LITTLE_ENDIAN_BITFIELD)
141 __be32 reserved:5,
142 override:1,
143 solicited:1,
144 router:1,
145 reserved2:24;
146#elif defined(__BIG_ENDIAN_BITFIELD)
147 __be32 router:1,
148 solicited:1,
149 override:1,
150 reserved:29;
151#else
152#error "Please fix <asm/byteorder.h>"
153#endif
154 } u_nd_advt;
155
156 /* struct icmpv6_nd_ra - Router Advertisement format */
157 struct icmpv6_nd_ra {
158 u8 hop_limit;
159#if defined(__LITTLE_ENDIAN_BITFIELD)
160 u8 reserved:6,
161 other:1,
162 managed:1;
163
164#elif defined(__BIG_ENDIAN_BITFIELD)
165 u8 managed:1,
166 other:1,
167 reserved:6;
168#else
169#error "Please fix <asm/byteorder.h>"
170#endif
171 __be16 rt_lifetime;
172 } u_nd_ra;
173 } icmp6_dataun;
174#define icmp6_identifier icmp6_dataun.u_echo.identifier
175#define icmp6_sequence icmp6_dataun.u_echo.sequence
176#define icmp6_pointer icmp6_dataun.un_data32[0]
177#define icmp6_mtu icmp6_dataun.un_data32[0]
178#define icmp6_unused icmp6_dataun.un_data32[0]
179#define icmp6_maxdelay icmp6_dataun.un_data16[0]
180#define icmp6_router icmp6_dataun.u_nd_advt.router
181#define icmp6_solicited icmp6_dataun.u_nd_advt.solicited
182#define icmp6_override icmp6_dataun.u_nd_advt.override
183#define icmp6_ndiscreserved icmp6_dataun.u_nd_advt.reserved
184#define icmp6_hop_limit icmp6_dataun.u_nd_ra.hop_limit
185#define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
186#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
187#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
Sergei Antonovdc4d9c22023-01-18 20:52:18 +0300188} __packed;
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300189
Ehsan Mohandesia0d6d272023-04-21 17:08:21 -0700190/*
191 * struct icmp6_ra_prefix_info - Prefix Information option of the ICMPv6 message
192 * The Prefix Information option provides hosts with on-link prefixes and
193 * prefixes for Address Autoconfiguration. Refer to RFC 4861 for more info.
194 */
195struct icmp6_ra_prefix_info {
196 u8 type; /* Type is 3 for Prefix Information. */
197 u8 len; /* Len is 4 for Prefix Information. */
198 /* The number of leading bits in the Prefix that are valid. */
199 u8 prefix_len;
200 u8 reserved1:6, /* MUST be ignored by the receiver. */
201 aac:1, /* autonomous address-configuration flag */
202 /* Indicates that this prefix can be used for on-link determination. */
203 on_link:1;
204 /*
205 * The length of time in seconds that the prefix is valid for the
206 * purpose of on-link determination.
207 */
208 __be32 valid_lifetime;
209 /* The length of time addresses remain preferred. */
210 __be32 preferred_lifetime;
211 __be32 reserved2; /* MUST be ignored by the receiver. */
212 /*
213 * Prefix is an IP address or a prefix of an IP address. The Prefix
214 * Length field contains the number of valid leading bits in the prefix.
215 * The bits in the prefix after the prefix length are reserved and MUST
216 * be initialized to zero by the sender and ignored by the receiver.
217 */
218 struct in6_addr prefix;
Ehsan Mohandesib38292c2023-05-18 11:24:39 -0700219} __packed;
Ehsan Mohandesia0d6d272023-04-21 17:08:21 -0700220
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300221extern struct in6_addr const net_null_addr_ip6; /* NULL IPv6 address */
222extern struct in6_addr net_gateway6; /* Our gateways IPv6 address */
223extern struct in6_addr net_ip6; /* Our IPv6 addr (0 = unknown) */
224extern struct in6_addr net_link_local_ip6; /* Our link local IPv6 addr */
225extern u32 net_prefix_length; /* Our prefixlength (0 = unknown) */
226extern struct in6_addr net_server_ip6; /* Server IPv6 addr (0 = unknown) */
Viacheslav Mitrofanove03c8aa2022-12-02 12:18:08 +0300227extern struct in6_addr net_ping_ip6; /* the ipv6 address to ping */
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300228extern bool use_ip6;
229
Viacheslav Mitrofanovfb7968c2022-12-02 12:18:02 +0300230#if IS_ENABLED(CONFIG_IPV6)
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300231/**
232 * string_to_ip6() - Convert IPv6 string addr to inner IPV6 addr format
233 *
234 * Examples of valid strings:
235 * 2001:db8::0:1234:1
236 * 2001:0db8:0000:0000:0000:0000:1234:0001
237 * ::1
238 * ::ffff:192.168.1.1
239 *
240 * Examples of invalid strings
241 * 2001:db8::0::0 (:: can only appear once)
242 * 2001:db8:192.168.1.1::1 (v4 part can only appear at the end)
243 * 192.168.1.1 (we don't implicity map v4)
244 *
245 * @s: IPv6 string addr format
246 * @len: IPv6 string addr length
247 * @addr: converted IPv6 addr
248 * Return: 0 if conversion successful, -EINVAL if fail
249 */
Viacheslav Mitrofanovfb7968c2022-12-02 12:18:02 +0300250int string_to_ip6(const char *s, size_t len, struct in6_addr *addr);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300251
252/**
253 * ip6_is_unspecified_addr() - Check if IPv6 addr is not set i.e. is zero
254 *
255 * @addr: IPv6 addr
256 * Return: 0 if addr is not set, -1 if is set
257 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300258int ip6_is_unspecified_addr(struct in6_addr *addr);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300259
260/**
261 * ip6_is_our_addr() - Check if IPv6 addr belongs to our host addr
262 *
263 * We have 2 addresses that we should respond to. A link local address and a
264 * global address. This returns true if the specified address matches either
265 * of these.
266 *
267 * @addr: addr to check
268 * Return: 0 if addr is our, -1 otherwise
269 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300270int ip6_is_our_addr(struct in6_addr *addr);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300271
272/**
273 * ip6_addr_in_subnet() - Check if two IPv6 addresses are in the same subnet
274 *
275 * @our_addr: first IPv6 addr
276 * @neigh_addr: second IPv6 addr
277 * @prefix_length: network mask length
278 * Return: 0 if two addresses in the same subnet, -1 otherwise
279 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300280int ip6_addr_in_subnet(struct in6_addr *our_addr, struct in6_addr *neigh_addr,
281 u32 prefix_length);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300282
283/**
284 * ip6_make_lladd() - rMake up IPv6 Link Local address
285 *
286 * @lladdr: formed IPv6 Link Local address
287 * @enetaddr: MAC addr of a device
288 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300289void ip6_make_lladdr(struct in6_addr *lladr, unsigned char const enetaddr[6]);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300290
291/**
292 * ip6_make_snma() - aMake up Solicited Node Multicast Address from IPv6 addr
293 *
294 * @mcast_addr: formed SNMA addr
295 * @ip6_addr: base IPv6 addr
296 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300297void ip6_make_snma(struct in6_addr *mcast_addr, struct in6_addr *ip6_addr);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300298
299/**
300 * ip6_make_mult_ethdstaddr() - Make up IPv6 multicast addr
301 *
302 * @enetaddr: MAC addr of a device
303 * @mcast_addr: formed IPv6 multicast addr
304 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300305void ip6_make_mult_ethdstaddr(unsigned char enetaddr[6],
306 struct in6_addr *mcast_addr);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300307
308/**
309 * csum_partial() - Compute an internet checksum
310 *
311 * @buff: buffer to be checksummed
312 * @len: length of buffer
313 * @sum: initial sum to be added in
314 * Return: internet checksum of the buffer
315 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300316unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300317
318/**
319 * csum_ipv6_magic() - Compute checksum of IPv6 "psuedo-header" per RFC2460 section 8.1
320 *
321 * @saddr: source IPv6 addr
322 * @daddr: destination IPv6 add
323 * @len: data length to be checksummed
324 * @proto: IPv6 above protocol code
325 * @csum: upper layer checksum
326 * Return: computed checksum
327 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300328unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
329 struct in6_addr *daddr, u16 len,
330 unsigned short proto, unsigned int csum);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300331
332/**
333 * ip6_add_hdr() - Make up IPv6 header
334 *
335 * @xip: pointer to IPv6 header to be formed
336 * @src: source IPv6 addr
337 * @dest: destination IPv6 addr
338 * @nextheader: next header type
339 * @hoplimit: hop limit
340 * @payload_len: payload length
341 * Return: IPv6 header length
342 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300343int ip6_add_hdr(uchar *xip, struct in6_addr *src, struct in6_addr *dest,
344 int nextheader, int hoplimit, int payload_len);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300345
346/**
347 * net_send_udp_packet6() - Make up UDP packet and send it
348 *
349 * @ether: destination MAC addr
350 * @dest: destination IPv6 addr
351 * @dport: destination port
352 * @sport: source port
353 * @len: UDP packet length
354 * Return: 0 if send successfully, -1 otherwise
355 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300356int net_send_udp_packet6(uchar *ether, struct in6_addr *dest, int dport,
357 int sport, int len);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300358
359/**
360 * net_ip6_handler() - Handle IPv6 packet
361 *
362 * @et: pointer to the beginning of the packet
363 * @ip6: pointer to the beginning of IPv6 protocol
364 * @len: incoming packet len
365 * Return: 0 if handle packet successfully, -EINVAL in case of invalid protocol
366 */
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300367int net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len);
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300368
369/**
370 * net_copy_ip6() - Copy IPv6 addr
371 *
372 * @to: destination IPv6 addr
373 * @from: source IPv6 addr
374 */
375static inline void net_copy_ip6(void *to, const void *from)
376{
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300377 memcpy((void *)to, from, sizeof(struct in6_addr));
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300378}
Viacheslav Mitrofanov99819ad2022-12-02 12:18:05 +0300379#else
380static inline int
381string_to_ip6(const char *s, size_t len, struct in6_addr *addr)
382{
383 return -EINVAL;
384}
385
386static inline int ip6_is_unspecified_addr(struct in6_addr *addr)
387{
388 return -1;
389}
390
391static inline int ip6_is_our_addr(struct in6_addr *addr)
392{
393 return -1;
394}
395
396static inline int
397ip6_addr_in_subnet(struct in6_addr *our_addr, struct in6_addr *neigh_addr,
398 u32 prefix_length)
399{
400 return -1;
401}
402
403static inline void
404ip6_make_lladdr(struct in6_addr *lladdr, unsigned char const enetaddr[6])
405{
406}
407
408static inline void
409ip6_make_snma(struct in6_addr *mcast_addr, struct in6_addr *ip6_addr)
410{
411}
412
413static inline void
414ip6_make_mult_ethdstaddr(unsigned char enetaddr[6],
415 struct in6_addr *mcast_addr)
416{
417}
418
419static inline unsigned int
420csum_partial(const unsigned char *buff, int len, unsigned int sum)
421{
422 return 0;
423}
424
425static inline unsigned short
426csum_ipv6_magic(struct in6_addr *saddr,
427 struct in6_addr *daddr, u16 len,
428 unsigned short proto, unsigned int csum)
429{
430 return 0;
431}
432
433static inline unsigned int
434ip6_add_hdr(uchar *xip, struct in6_addr *src, struct in6_addr *dest,
435 int nextheader, int hoplimit, int payload_len)
436{
437 return 0;
438}
439
440static inline int
441net_send_udp_packet6(uchar *ether, struct in6_addr *dest,
442 int dport, int sport, int len)
443{
444 return -1;
445}
446
447static inline int
448net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6,
449 int len)
450{
451 return -EINVAL;
452}
453
454static inline void net_copy_ip6(void *to, const void *from)
455{
456}
457#endif
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300458
Viacheslav Mitrofanove03c8aa2022-12-02 12:18:08 +0300459#if IS_ENABLED(CONFIG_CMD_PING6)
460/* Send ping requset */
461void ping6_start(void);
462
463/**
464 * ping6_receive() - Handle reception of ICMPv6 echo request/reply
465 *
466 * @et: pointer to incoming patcket
467 * @ip6: pointer to IPv6 protocol
468 * @len: packet length
469 * Return: 0 if success, -EINVAL in case of failure during reception
470 */
471int ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len);
472#else
473static inline void ping6_start(void)
474{
475}
476
477static inline
478int ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
479{
480 return -EINVAL;
481}
482#endif /* CONFIG_CMD_PING6 */
483
Viacheslav Mitrofanov7674b122022-12-02 12:17:58 +0300484#endif /* __NET6_H__ */