ipv6.c (a432c771e2d9bc059ffe3028faf040c08b6a9f98) ipv6.c (0c5dc070ff3d6246d22ddd931f23a6266249e3db)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/* SCTP kernel implementation
3 * (C) Copyright IBM Corp. 2002, 2004
4 * Copyright (c) 2001 Nokia, Inc.
5 * Copyright (c) 2001 La Monte H.P. Yarroll
6 * Copyright (c) 2002-2003 Intel Corp.
7 *
8 * This file is part of the SCTP kernel implementation

--- 108 unchanged lines hidden (view full) ---

117
118 return NOTIFY_DONE;
119}
120
121static struct notifier_block sctp_inet6addr_notifier = {
122 .notifier_call = sctp_inet6addr_event,
123};
124
1// SPDX-License-Identifier: GPL-2.0-or-later
2/* SCTP kernel implementation
3 * (C) Copyright IBM Corp. 2002, 2004
4 * Copyright (c) 2001 Nokia, Inc.
5 * Copyright (c) 2001 La Monte H.P. Yarroll
6 * Copyright (c) 2002-2003 Intel Corp.
7 *
8 * This file is part of the SCTP kernel implementation

--- 108 unchanged lines hidden (view full) ---

117
118 return NOTIFY_DONE;
119}
120
121static struct notifier_block sctp_inet6addr_notifier = {
122 .notifier_call = sctp_inet6addr_event,
123};
124
125static void sctp_v6_err_handle(struct sctp_transport *t, struct sk_buff *skb,
126 __u8 type, __u8 code, __u32 info)
125/* ICMP error handler. */
126static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
127 u8 type, u8 code, int offset, __be32 info)
127{
128{
128 struct sctp_association *asoc = t->asoc;
129 struct sock *sk = asoc->base.sk;
129 struct inet6_dev *idev;
130 struct sock *sk;
131 struct sctp_association *asoc;
132 struct sctp_transport *transport;
130 struct ipv6_pinfo *np;
133 struct ipv6_pinfo *np;
131 int err = 0;
134 __u16 saveip, savesctp;
135 int err, ret = 0;
136 struct net *net = dev_net(skb->dev);
132
137
138 idev = in6_dev_get(skb->dev);
139
140 /* Fix up skb to look at the embedded net header. */
141 saveip = skb->network_header;
142 savesctp = skb->transport_header;
143 skb_reset_network_header(skb);
144 skb_set_transport_header(skb, offset);
145 sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
146 /* Put back, the original pointers. */
147 skb->network_header = saveip;
148 skb->transport_header = savesctp;
149 if (!sk) {
150 __ICMP6_INC_STATS(net, idev, ICMP6_MIB_INERRORS);
151 ret = -ENOENT;
152 goto out;
153 }
154
155 /* Warning: The sock lock is held. Remember to call
156 * sctp_err_finish!
157 */
158
133 switch (type) {
134 case ICMPV6_PKT_TOOBIG:
135 if (ip6_sk_accept_pmtu(sk))
159 switch (type) {
160 case ICMPV6_PKT_TOOBIG:
161 if (ip6_sk_accept_pmtu(sk))
136 sctp_icmp_frag_needed(sk, asoc, t, info);
137 return;
162 sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
163 goto out_unlock;
138 case ICMPV6_PARAMPROB:
139 if (ICMPV6_UNK_NEXTHDR == code) {
164 case ICMPV6_PARAMPROB:
165 if (ICMPV6_UNK_NEXTHDR == code) {
140 sctp_icmp_proto_unreachable(sk, asoc, t);
141 return;
166 sctp_icmp_proto_unreachable(sk, asoc, transport);
167 goto out_unlock;
142 }
143 break;
144 case NDISC_REDIRECT:
168 }
169 break;
170 case NDISC_REDIRECT:
145 sctp_icmp_redirect(sk, t, skb);
146 return;
171 sctp_icmp_redirect(sk, transport, skb);
172 goto out_unlock;
147 default:
148 break;
149 }
150
151 np = inet6_sk(sk);
152 icmpv6_err_convert(type, code, &err);
153 if (!sock_owned_by_user(sk) && np->recverr) {
154 sk->sk_err = err;
155 sk->sk_error_report(sk);
173 default:
174 break;
175 }
176
177 np = inet6_sk(sk);
178 icmpv6_err_convert(type, code, &err);
179 if (!sock_owned_by_user(sk) && np->recverr) {
180 sk->sk_err = err;
181 sk->sk_error_report(sk);
156 } else {
182 } else { /* Only an error on timeout */
157 sk->sk_err_soft = err;
158 }
183 sk->sk_err_soft = err;
184 }
159}
160
185
161/* ICMP error handler. */
162static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
163 u8 type, u8 code, int offset, __be32 info)
164{
165 struct net *net = dev_net(skb->dev);
166 struct sctp_transport *transport;
167 struct sctp_association *asoc;
168 __u16 saveip, savesctp;
169 struct sock *sk;
170
171 /* Fix up skb to look at the embedded net header. */
172 saveip = skb->network_header;
173 savesctp = skb->transport_header;
174 skb_reset_network_header(skb);
175 skb_set_transport_header(skb, offset);
176 sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
177 /* Put back, the original pointers. */
178 skb->network_header = saveip;
179 skb->transport_header = savesctp;
180 if (!sk) {
181 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
182 return -ENOENT;
183 }
184
185 sctp_v6_err_handle(transport, skb, type, code, ntohl(info));
186out_unlock:
186 sctp_err_finish(sk, transport);
187 sctp_err_finish(sk, transport);
188out:
189 if (likely(idev != NULL))
190 in6_dev_put(idev);
187
191
188 return 0;
192 return ret;
189}
190
193}
194
191int sctp_udp_v6_err(struct sock *sk, struct sk_buff *skb)
192{
193 struct net *net = dev_net(skb->dev);
194 struct sctp_association *asoc;
195 struct sctp_transport *t;
196 struct icmp6hdr *hdr;
197 __u32 info = 0;
198
199 skb->transport_header += sizeof(struct udphdr);
200 sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &t);
201 if (!sk) {
202 __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
203 return -ENOENT;
204 }
205
206 skb->transport_header -= sizeof(struct udphdr);
207 hdr = (struct icmp6hdr *)(skb_network_header(skb) - sizeof(struct icmp6hdr));
208 if (hdr->icmp6_type == NDISC_REDIRECT) {
209 /* can't be handled without outer ip6hdr known, leave it to udpv6_err */
210 sctp_err_finish(sk, t);
211 return 0;
212 }
213 if (hdr->icmp6_type == ICMPV6_PKT_TOOBIG)
214 info = ntohl(hdr->icmp6_mtu);
215 sctp_v6_err_handle(t, skb, hdr->icmp6_type, hdr->icmp6_code, info);
216
217 sctp_err_finish(sk, t);
218 return 1;
219}
220
221static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)
222{
223 struct dst_entry *dst = dst_clone(t->dst);
224 struct flowi6 *fl6 = &t->fl.u.ip6;
225 struct sock *sk = skb->sk;
226 struct ipv6_pinfo *np = inet6_sk(sk);
227 __u8 tclass = np->tclass;
228 __be32 label;

--- 343 unchanged lines hidden (view full) ---

572 sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff);
573 sk->sk_v6_daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
574 } else {
575 sk->sk_v6_daddr = addr->v6.sin6_addr;
576 }
577}
578
579/* Initialize a sctp_addr from an address parameter. */
195static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)
196{
197 struct dst_entry *dst = dst_clone(t->dst);
198 struct flowi6 *fl6 = &t->fl.u.ip6;
199 struct sock *sk = skb->sk;
200 struct ipv6_pinfo *np = inet6_sk(sk);
201 __u8 tclass = np->tclass;
202 __be32 label;

--- 343 unchanged lines hidden (view full) ---

546 sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff);
547 sk->sk_v6_daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
548 } else {
549 sk->sk_v6_daddr = addr->v6.sin6_addr;
550 }
551}
552
553/* Initialize a sctp_addr from an address parameter. */
580static void sctp_v6_from_addr_param(union sctp_addr *addr,
554static bool sctp_v6_from_addr_param(union sctp_addr *addr,
581 union sctp_addr_param *param,
582 __be16 port, int iif)
583{
555 union sctp_addr_param *param,
556 __be16 port, int iif)
557{
558 if (ntohs(param->v6.param_hdr.length) < sizeof(struct sctp_ipv6addr_param))
559 return false;
560
584 addr->v6.sin6_family = AF_INET6;
585 addr->v6.sin6_port = port;
586 addr->v6.sin6_flowinfo = 0; /* BUG */
587 addr->v6.sin6_addr = param->v6.addr;
588 addr->v6.sin6_scope_id = iif;
561 addr->v6.sin6_family = AF_INET6;
562 addr->v6.sin6_port = port;
563 addr->v6.sin6_flowinfo = 0; /* BUG */
564 addr->v6.sin6_addr = param->v6.addr;
565 addr->v6.sin6_scope_id = iif;
566
567 return true;
589}
590
591/* Initialize an address parameter from a sctp_addr and return the length
592 * of the address parameter.
593 */
594static int sctp_v6_to_addr_param(const union sctp_addr *addr,
595 union sctp_addr_param *param)
596{

--- 615 unchanged lines hidden ---
568}
569
570/* Initialize an address parameter from a sctp_addr and return the length
571 * of the address parameter.
572 */
573static int sctp_v6_to_addr_param(const union sctp_addr *addr,
574 union sctp_addr_param *param)
575{

--- 615 unchanged lines hidden ---