blob: 1e766aa72092f1ba727242a0c520eb3092b4dc40 [file] [log] [blame]
Viacheslav Mitrofanov33b50662022-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>
14#include <linux/ctype.h>
15
16/* struct in6_addr - 128 bits long IPv6 address */
17struct in6_addr {
18 union {
19 u8 u6_addr8[16];
20 __be16 u6_addr16[8];
21 __be32 u6_addr32[4];
22 } in6_u;
23
24#define s6_addr in6_u.u6_addr8
25#define s6_addr16 in6_u.u6_addr16
26#define s6_addr32 in6_u.u6_addr32
Sergei Antonov9bc80c02023-01-18 20:52:18 +030027} __packed;
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +030028
29#define IN6ADDRSZ sizeof(struct in6_addr)
30#define INETHADDRSZ sizeof(net_ethaddr)
31
32#define PROT_IP6 0x86DD /* IPv6 protocol */
33#define PROT_ICMPV6 58 /* ICMPv6 protocol*/
34
35#define IPV6_ADDRSCOPE_INTF 0x01
36#define IPV6_ADDRSCOPE_LINK 0x02
37#define IPV6_ADDRSCOPE_AMDIN 0x04
38#define IPV6_ADDRSCOPE_SITE 0x05
39#define IPV6_ADDRSCOPE_ORG 0x08
40#define IPV6_ADDRSCOPE_GLOBAL 0x0E
41
42#define USE_IP6_CMD_PARAM "-ipv6"
43
44/**
45 * struct ipv6hdr - Internet Protocol V6 (IPv6) header.
46 *
47 * IPv6 packet header as defined in RFC 2460.
48 */
49struct ip6_hdr {
50#if defined(__LITTLE_ENDIAN_BITFIELD)
51 u8 priority:4,
52 version:4;
53#elif defined(__BIG_ENDIAN_BITFIELD)
54 u8 version:4,
55 priority:4;
56#else
57#error "Please fix <asm/byteorder.h>"
58#endif
59 u8 flow_lbl[3];
60 __be16 payload_len;
61 u8 nexthdr;
62 u8 hop_limit;
63 struct in6_addr saddr;
64 struct in6_addr daddr;
Sergei Antonov9bc80c02023-01-18 20:52:18 +030065} __packed;
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +030066#define IP6_HDR_SIZE (sizeof(struct ip6_hdr))
67
68/* struct udp_hdr - User Datagram Protocol header */
69struct udp_hdr {
70 u16 udp_src; /* UDP source port */
71 u16 udp_dst; /* UDP destination port */
72 u16 udp_len; /* Length of UDP packet */
73 u16 udp_xsum; /* Checksum */
74} __packed;
75
76/*
77 * Handy for static initialisations of struct in6_addr, atlhough the
78 * c99 '= { 0 }' idiom might work depending on you compiler.
79 */
80#define ZERO_IPV6_ADDR { { { 0x00, 0x00, 0x00, 0x00, \
81 0x00, 0x00, 0x00, 0x00, \
82 0x00, 0x00, 0x00, 0x00, \
83 0x00, 0x00, 0x00, 0x00 } } }
Ehsan Mohandesi6de98b62023-04-21 17:08:21 -070084/*
85 * All-routers multicast address is the link-local scope address to reach all
86 * routers.
87 */
88#define ALL_ROUTERS_MULT_ADDR { { { 0xFF, 0x02, 0x00, 0x00, \
89 0x00, 0x00, 0x00, 0x00, \
90 0x00, 0x00, 0x00, 0x00, \
91 0x00, 0x00, 0x00, 0x02 } } }
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +030092
93#define IPV6_LINK_LOCAL_PREFIX 0xfe80
Ehsan Mohandesi6de98b62023-04-21 17:08:21 -070094#define IPV6_LINK_LOCAL_MASK 0xffb0 /* The first 10-bit of address mask. */
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +030095
96/* hop limit for neighbour discovery packets */
97#define IPV6_NDISC_HOPLIMIT 255
98#define NDISC_TIMEOUT 5000UL
99#define NDISC_TIMEOUT_COUNT 3
100
101/* struct icmp6hdr - Internet Control Message Protocol header for IPV6 */
102struct icmp6hdr {
103 u8 icmp6_type;
104#define IPV6_ICMP_ECHO_REQUEST 128
105#define IPV6_ICMP_ECHO_REPLY 129
106#define IPV6_NDISC_ROUTER_SOLICITATION 133
107#define IPV6_NDISC_ROUTER_ADVERTISEMENT 134
108#define IPV6_NDISC_NEIGHBOUR_SOLICITATION 135
109#define IPV6_NDISC_NEIGHBOUR_ADVERTISEMENT 136
110#define IPV6_NDISC_REDIRECT 137
111 u8 icmp6_code;
112 __be16 icmp6_cksum;
113
114 /* ICMPv6 data */
115 union {
116 __be32 un_data32[1];
117 __be16 un_data16[2];
118 u8 un_data8[4];
119
120 /* struct icmpv6_echo - echo request/reply message format */
121 struct icmpv6_echo {
122 __be16 identifier;
123 __be16 sequence;
124 } u_echo;
125
126 /* struct icmpv6_nd_advt - Neighbor Advertisement format */
127 struct icmpv6_nd_advt {
128#if defined(__LITTLE_ENDIAN_BITFIELD)
129 __be32 reserved:5,
130 override:1,
131 solicited:1,
132 router:1,
133 reserved2:24;
134#elif defined(__BIG_ENDIAN_BITFIELD)
135 __be32 router:1,
136 solicited:1,
137 override:1,
138 reserved:29;
139#else
140#error "Please fix <asm/byteorder.h>"
141#endif
142 } u_nd_advt;
143
144 /* struct icmpv6_nd_ra - Router Advertisement format */
145 struct icmpv6_nd_ra {
146 u8 hop_limit;
147#if defined(__LITTLE_ENDIAN_BITFIELD)
148 u8 reserved:6,
149 other:1,
150 managed:1;
151
152#elif defined(__BIG_ENDIAN_BITFIELD)
153 u8 managed:1,
154 other:1,
155 reserved:6;
156#else
157#error "Please fix <asm/byteorder.h>"
158#endif
159 __be16 rt_lifetime;
160 } u_nd_ra;
161 } icmp6_dataun;
162#define icmp6_identifier icmp6_dataun.u_echo.identifier
163#define icmp6_sequence icmp6_dataun.u_echo.sequence
164#define icmp6_pointer icmp6_dataun.un_data32[0]
165#define icmp6_mtu icmp6_dataun.un_data32[0]
166#define icmp6_unused icmp6_dataun.un_data32[0]
167#define icmp6_maxdelay icmp6_dataun.un_data16[0]
168#define icmp6_router icmp6_dataun.u_nd_advt.router
169#define icmp6_solicited icmp6_dataun.u_nd_advt.solicited
170#define icmp6_override icmp6_dataun.u_nd_advt.override
171#define icmp6_ndiscreserved icmp6_dataun.u_nd_advt.reserved
172#define icmp6_hop_limit icmp6_dataun.u_nd_ra.hop_limit
173#define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
174#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
175#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
Sergei Antonov9bc80c02023-01-18 20:52:18 +0300176} __packed;
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300177
Ehsan Mohandesi6de98b62023-04-21 17:08:21 -0700178/*
179 * struct icmp6_ra_prefix_info - Prefix Information option of the ICMPv6 message
180 * The Prefix Information option provides hosts with on-link prefixes and
181 * prefixes for Address Autoconfiguration. Refer to RFC 4861 for more info.
182 */
183struct icmp6_ra_prefix_info {
184 u8 type; /* Type is 3 for Prefix Information. */
185 u8 len; /* Len is 4 for Prefix Information. */
186 /* The number of leading bits in the Prefix that are valid. */
187 u8 prefix_len;
188 u8 reserved1:6, /* MUST be ignored by the receiver. */
189 aac:1, /* autonomous address-configuration flag */
190 /* Indicates that this prefix can be used for on-link determination. */
191 on_link:1;
192 /*
193 * The length of time in seconds that the prefix is valid for the
194 * purpose of on-link determination.
195 */
196 __be32 valid_lifetime;
197 /* The length of time addresses remain preferred. */
198 __be32 preferred_lifetime;
199 __be32 reserved2; /* MUST be ignored by the receiver. */
200 /*
201 * Prefix is an IP address or a prefix of an IP address. The Prefix
202 * Length field contains the number of valid leading bits in the prefix.
203 * The bits in the prefix after the prefix length are reserved and MUST
204 * be initialized to zero by the sender and ignored by the receiver.
205 */
206 struct in6_addr prefix;
Ehsan Mohandesi1196e522023-05-18 11:24:39 -0700207} __packed;
Ehsan Mohandesi6de98b62023-04-21 17:08:21 -0700208
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300209extern struct in6_addr const net_null_addr_ip6; /* NULL IPv6 address */
210extern struct in6_addr net_gateway6; /* Our gateways IPv6 address */
211extern struct in6_addr net_ip6; /* Our IPv6 addr (0 = unknown) */
212extern struct in6_addr net_link_local_ip6; /* Our link local IPv6 addr */
213extern u32 net_prefix_length; /* Our prefixlength (0 = unknown) */
214extern struct in6_addr net_server_ip6; /* Server IPv6 addr (0 = unknown) */
Viacheslav Mitrofanoveeb0a2c2022-12-02 12:18:08 +0300215extern struct in6_addr net_ping_ip6; /* the ipv6 address to ping */
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300216extern bool use_ip6;
217
Viacheslav Mitrofanov2f7f2f22022-12-02 12:18:02 +0300218#if IS_ENABLED(CONFIG_IPV6)
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300219/**
220 * string_to_ip6() - Convert IPv6 string addr to inner IPV6 addr format
221 *
222 * Examples of valid strings:
223 * 2001:db8::0:1234:1
224 * 2001:0db8:0000:0000:0000:0000:1234:0001
225 * ::1
226 * ::ffff:192.168.1.1
227 *
228 * Examples of invalid strings
229 * 2001:db8::0::0 (:: can only appear once)
230 * 2001:db8:192.168.1.1::1 (v4 part can only appear at the end)
231 * 192.168.1.1 (we don't implicity map v4)
232 *
233 * @s: IPv6 string addr format
234 * @len: IPv6 string addr length
235 * @addr: converted IPv6 addr
236 * Return: 0 if conversion successful, -EINVAL if fail
237 */
Viacheslav Mitrofanov2f7f2f22022-12-02 12:18:02 +0300238int string_to_ip6(const char *s, size_t len, struct in6_addr *addr);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300239
240/**
241 * ip6_is_unspecified_addr() - Check if IPv6 addr is not set i.e. is zero
242 *
243 * @addr: IPv6 addr
244 * Return: 0 if addr is not set, -1 if is set
245 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300246int ip6_is_unspecified_addr(struct in6_addr *addr);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300247
248/**
249 * ip6_is_our_addr() - Check if IPv6 addr belongs to our host addr
250 *
251 * We have 2 addresses that we should respond to. A link local address and a
252 * global address. This returns true if the specified address matches either
253 * of these.
254 *
255 * @addr: addr to check
256 * Return: 0 if addr is our, -1 otherwise
257 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300258int ip6_is_our_addr(struct in6_addr *addr);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300259
260/**
261 * ip6_addr_in_subnet() - Check if two IPv6 addresses are in the same subnet
262 *
263 * @our_addr: first IPv6 addr
264 * @neigh_addr: second IPv6 addr
265 * @prefix_length: network mask length
266 * Return: 0 if two addresses in the same subnet, -1 otherwise
267 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300268int ip6_addr_in_subnet(struct in6_addr *our_addr, struct in6_addr *neigh_addr,
269 u32 prefix_length);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300270
271/**
272 * ip6_make_lladd() - rMake up IPv6 Link Local address
273 *
274 * @lladdr: formed IPv6 Link Local address
275 * @enetaddr: MAC addr of a device
276 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300277void ip6_make_lladdr(struct in6_addr *lladr, unsigned char const enetaddr[6]);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300278
279/**
280 * ip6_make_snma() - aMake up Solicited Node Multicast Address from IPv6 addr
281 *
282 * @mcast_addr: formed SNMA addr
283 * @ip6_addr: base IPv6 addr
284 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300285void ip6_make_snma(struct in6_addr *mcast_addr, struct in6_addr *ip6_addr);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300286
287/**
288 * ip6_make_mult_ethdstaddr() - Make up IPv6 multicast addr
289 *
290 * @enetaddr: MAC addr of a device
291 * @mcast_addr: formed IPv6 multicast addr
292 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300293void ip6_make_mult_ethdstaddr(unsigned char enetaddr[6],
294 struct in6_addr *mcast_addr);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300295
296/**
297 * csum_partial() - Compute an internet checksum
298 *
299 * @buff: buffer to be checksummed
300 * @len: length of buffer
301 * @sum: initial sum to be added in
302 * Return: internet checksum of the buffer
303 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300304unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300305
306/**
307 * csum_ipv6_magic() - Compute checksum of IPv6 "psuedo-header" per RFC2460 section 8.1
308 *
309 * @saddr: source IPv6 addr
310 * @daddr: destination IPv6 add
311 * @len: data length to be checksummed
312 * @proto: IPv6 above protocol code
313 * @csum: upper layer checksum
314 * Return: computed checksum
315 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300316unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
317 struct in6_addr *daddr, u16 len,
318 unsigned short proto, unsigned int csum);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300319
320/**
321 * ip6_add_hdr() - Make up IPv6 header
322 *
323 * @xip: pointer to IPv6 header to be formed
324 * @src: source IPv6 addr
325 * @dest: destination IPv6 addr
326 * @nextheader: next header type
327 * @hoplimit: hop limit
328 * @payload_len: payload length
329 * Return: IPv6 header length
330 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300331int ip6_add_hdr(uchar *xip, struct in6_addr *src, struct in6_addr *dest,
332 int nextheader, int hoplimit, int payload_len);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300333
334/**
335 * net_send_udp_packet6() - Make up UDP packet and send it
336 *
337 * @ether: destination MAC addr
338 * @dest: destination IPv6 addr
339 * @dport: destination port
340 * @sport: source port
341 * @len: UDP packet length
342 * Return: 0 if send successfully, -1 otherwise
343 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300344int net_send_udp_packet6(uchar *ether, struct in6_addr *dest, int dport,
345 int sport, int len);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300346
347/**
348 * net_ip6_handler() - Handle IPv6 packet
349 *
350 * @et: pointer to the beginning of the packet
351 * @ip6: pointer to the beginning of IPv6 protocol
352 * @len: incoming packet len
353 * Return: 0 if handle packet successfully, -EINVAL in case of invalid protocol
354 */
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300355int net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len);
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300356
357/**
358 * net_copy_ip6() - Copy IPv6 addr
359 *
360 * @to: destination IPv6 addr
361 * @from: source IPv6 addr
362 */
363static inline void net_copy_ip6(void *to, const void *from)
364{
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300365 memcpy((void *)to, from, sizeof(struct in6_addr));
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300366}
Viacheslav Mitrofanov1feb6972022-12-02 12:18:05 +0300367#else
368static inline int
369string_to_ip6(const char *s, size_t len, struct in6_addr *addr)
370{
371 return -EINVAL;
372}
373
374static inline int ip6_is_unspecified_addr(struct in6_addr *addr)
375{
376 return -1;
377}
378
379static inline int ip6_is_our_addr(struct in6_addr *addr)
380{
381 return -1;
382}
383
384static inline int
385ip6_addr_in_subnet(struct in6_addr *our_addr, struct in6_addr *neigh_addr,
386 u32 prefix_length)
387{
388 return -1;
389}
390
391static inline void
392ip6_make_lladdr(struct in6_addr *lladdr, unsigned char const enetaddr[6])
393{
394}
395
396static inline void
397ip6_make_snma(struct in6_addr *mcast_addr, struct in6_addr *ip6_addr)
398{
399}
400
401static inline void
402ip6_make_mult_ethdstaddr(unsigned char enetaddr[6],
403 struct in6_addr *mcast_addr)
404{
405}
406
407static inline unsigned int
408csum_partial(const unsigned char *buff, int len, unsigned int sum)
409{
410 return 0;
411}
412
413static inline unsigned short
414csum_ipv6_magic(struct in6_addr *saddr,
415 struct in6_addr *daddr, u16 len,
416 unsigned short proto, unsigned int csum)
417{
418 return 0;
419}
420
421static inline unsigned int
422ip6_add_hdr(uchar *xip, struct in6_addr *src, struct in6_addr *dest,
423 int nextheader, int hoplimit, int payload_len)
424{
425 return 0;
426}
427
428static inline int
429net_send_udp_packet6(uchar *ether, struct in6_addr *dest,
430 int dport, int sport, int len)
431{
432 return -1;
433}
434
435static inline int
436net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6,
437 int len)
438{
439 return -EINVAL;
440}
441
442static inline void net_copy_ip6(void *to, const void *from)
443{
444}
445#endif
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300446
Viacheslav Mitrofanoveeb0a2c2022-12-02 12:18:08 +0300447#if IS_ENABLED(CONFIG_CMD_PING6)
448/* Send ping requset */
449void ping6_start(void);
450
451/**
452 * ping6_receive() - Handle reception of ICMPv6 echo request/reply
453 *
454 * @et: pointer to incoming patcket
455 * @ip6: pointer to IPv6 protocol
456 * @len: packet length
457 * Return: 0 if success, -EINVAL in case of failure during reception
458 */
459int ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len);
460#else
461static inline void ping6_start(void)
462{
463}
464
465static inline
466int ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
467{
468 return -EINVAL;
469}
470#endif /* CONFIG_CMD_PING6 */
471
Viacheslav Mitrofanov33b50662022-12-02 12:17:58 +0300472#endif /* __NET6_H__ */