162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * INET An implementation of the TCP/IP protocol suite for the LINUX 462306a36Sopenharmony_ci * operating system. INET is implemented using the BSD Socket 562306a36Sopenharmony_ci * interface as the means of communication with the user level. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * RAW - implementation of IP "raw" sockets. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Authors: Ross Biro 1062306a36Sopenharmony_ci * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Fixes: 1362306a36Sopenharmony_ci * Alan Cox : verify_area() fixed up 1462306a36Sopenharmony_ci * Alan Cox : ICMP error handling 1562306a36Sopenharmony_ci * Alan Cox : EMSGSIZE if you send too big a packet 1662306a36Sopenharmony_ci * Alan Cox : Now uses generic datagrams and shared 1762306a36Sopenharmony_ci * skbuff library. No more peek crashes, 1862306a36Sopenharmony_ci * no more backlogs 1962306a36Sopenharmony_ci * Alan Cox : Checks sk->broadcast. 2062306a36Sopenharmony_ci * Alan Cox : Uses skb_free_datagram/skb_copy_datagram 2162306a36Sopenharmony_ci * Alan Cox : Raw passes ip options too 2262306a36Sopenharmony_ci * Alan Cox : Setsocketopt added 2362306a36Sopenharmony_ci * Alan Cox : Fixed error return for broadcasts 2462306a36Sopenharmony_ci * Alan Cox : Removed wake_up calls 2562306a36Sopenharmony_ci * Alan Cox : Use ttl/tos 2662306a36Sopenharmony_ci * Alan Cox : Cleaned up old debugging 2762306a36Sopenharmony_ci * Alan Cox : Use new kernel side addresses 2862306a36Sopenharmony_ci * Arnt Gulbrandsen : Fixed MSG_DONTROUTE in raw sockets. 2962306a36Sopenharmony_ci * Alan Cox : BSD style RAW socket demultiplexing. 3062306a36Sopenharmony_ci * Alan Cox : Beginnings of mrouted support. 3162306a36Sopenharmony_ci * Alan Cox : Added IP_HDRINCL option. 3262306a36Sopenharmony_ci * Alan Cox : Skip broadcast check if BSDism set. 3362306a36Sopenharmony_ci * David S. Miller : New socket lookup architecture. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/types.h> 3762306a36Sopenharmony_ci#include <linux/atomic.h> 3862306a36Sopenharmony_ci#include <asm/byteorder.h> 3962306a36Sopenharmony_ci#include <asm/current.h> 4062306a36Sopenharmony_ci#include <linux/uaccess.h> 4162306a36Sopenharmony_ci#include <asm/ioctls.h> 4262306a36Sopenharmony_ci#include <linux/stddef.h> 4362306a36Sopenharmony_ci#include <linux/slab.h> 4462306a36Sopenharmony_ci#include <linux/errno.h> 4562306a36Sopenharmony_ci#include <linux/kernel.h> 4662306a36Sopenharmony_ci#include <linux/export.h> 4762306a36Sopenharmony_ci#include <linux/spinlock.h> 4862306a36Sopenharmony_ci#include <linux/sockios.h> 4962306a36Sopenharmony_ci#include <linux/socket.h> 5062306a36Sopenharmony_ci#include <linux/in.h> 5162306a36Sopenharmony_ci#include <linux/mroute.h> 5262306a36Sopenharmony_ci#include <linux/netdevice.h> 5362306a36Sopenharmony_ci#include <linux/in_route.h> 5462306a36Sopenharmony_ci#include <linux/route.h> 5562306a36Sopenharmony_ci#include <linux/skbuff.h> 5662306a36Sopenharmony_ci#include <linux/igmp.h> 5762306a36Sopenharmony_ci#include <net/net_namespace.h> 5862306a36Sopenharmony_ci#include <net/dst.h> 5962306a36Sopenharmony_ci#include <net/sock.h> 6062306a36Sopenharmony_ci#include <linux/ip.h> 6162306a36Sopenharmony_ci#include <linux/net.h> 6262306a36Sopenharmony_ci#include <net/ip.h> 6362306a36Sopenharmony_ci#include <net/icmp.h> 6462306a36Sopenharmony_ci#include <net/udp.h> 6562306a36Sopenharmony_ci#include <net/raw.h> 6662306a36Sopenharmony_ci#include <net/snmp.h> 6762306a36Sopenharmony_ci#include <net/tcp_states.h> 6862306a36Sopenharmony_ci#include <net/inet_common.h> 6962306a36Sopenharmony_ci#include <net/checksum.h> 7062306a36Sopenharmony_ci#include <net/xfrm.h> 7162306a36Sopenharmony_ci#include <linux/rtnetlink.h> 7262306a36Sopenharmony_ci#include <linux/proc_fs.h> 7362306a36Sopenharmony_ci#include <linux/seq_file.h> 7462306a36Sopenharmony_ci#include <linux/netfilter.h> 7562306a36Sopenharmony_ci#include <linux/netfilter_ipv4.h> 7662306a36Sopenharmony_ci#include <linux/compat.h> 7762306a36Sopenharmony_ci#include <linux/uio.h> 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistruct raw_frag_vec { 8062306a36Sopenharmony_ci struct msghdr *msg; 8162306a36Sopenharmony_ci union { 8262306a36Sopenharmony_ci struct icmphdr icmph; 8362306a36Sopenharmony_ci char c[1]; 8462306a36Sopenharmony_ci } hdr; 8562306a36Sopenharmony_ci int hlen; 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistruct raw_hashinfo raw_v4_hashinfo; 8962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(raw_v4_hashinfo); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciint raw_hash_sk(struct sock *sk) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; 9462306a36Sopenharmony_ci struct hlist_head *hlist; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci hlist = &h->ht[raw_hashfunc(sock_net(sk), inet_sk(sk)->inet_num)]; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci spin_lock(&h->lock); 9962306a36Sopenharmony_ci sk_add_node_rcu(sk, hlist); 10062306a36Sopenharmony_ci sock_set_flag(sk, SOCK_RCU_FREE); 10162306a36Sopenharmony_ci spin_unlock(&h->lock); 10262306a36Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(raw_hash_sk); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_civoid raw_unhash_sk(struct sock *sk) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci spin_lock(&h->lock); 11362306a36Sopenharmony_ci if (sk_del_node_init_rcu(sk)) 11462306a36Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 11562306a36Sopenharmony_ci spin_unlock(&h->lock); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(raw_unhash_sk); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cibool raw_v4_match(struct net *net, const struct sock *sk, unsigned short num, 12062306a36Sopenharmony_ci __be32 raddr, __be32 laddr, int dif, int sdif) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci const struct inet_sock *inet = inet_sk(sk); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (net_eq(sock_net(sk), net) && inet->inet_num == num && 12562306a36Sopenharmony_ci !(inet->inet_daddr && inet->inet_daddr != raddr) && 12662306a36Sopenharmony_ci !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && 12762306a36Sopenharmony_ci raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif)) 12862306a36Sopenharmony_ci return true; 12962306a36Sopenharmony_ci return false; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(raw_v4_match); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * 0 - deliver 13562306a36Sopenharmony_ci * 1 - block 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_cistatic int icmp_filter(const struct sock *sk, const struct sk_buff *skb) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct icmphdr _hdr; 14062306a36Sopenharmony_ci const struct icmphdr *hdr; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci hdr = skb_header_pointer(skb, skb_transport_offset(skb), 14362306a36Sopenharmony_ci sizeof(_hdr), &_hdr); 14462306a36Sopenharmony_ci if (!hdr) 14562306a36Sopenharmony_ci return 1; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (hdr->type < 32) { 14862306a36Sopenharmony_ci __u32 data = raw_sk(sk)->filter.data; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return ((1U << hdr->type) & data) != 0; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Do not block unknown ICMP types */ 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* IP input processing comes here for RAW socket delivery. 15862306a36Sopenharmony_ci * Caller owns SKB, so we must make clones. 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * RFC 1122: SHOULD pass TOS value up to the transport layer. 16162306a36Sopenharmony_ci * -> It does. And not only TOS, but all IP header. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_cistatic int raw_v4_input(struct net *net, struct sk_buff *skb, 16462306a36Sopenharmony_ci const struct iphdr *iph, int hash) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci int sdif = inet_sdif(skb); 16762306a36Sopenharmony_ci struct hlist_head *hlist; 16862306a36Sopenharmony_ci int dif = inet_iif(skb); 16962306a36Sopenharmony_ci int delivered = 0; 17062306a36Sopenharmony_ci struct sock *sk; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci hlist = &raw_v4_hashinfo.ht[hash]; 17362306a36Sopenharmony_ci rcu_read_lock(); 17462306a36Sopenharmony_ci sk_for_each_rcu(sk, hlist) { 17562306a36Sopenharmony_ci if (!raw_v4_match(net, sk, iph->protocol, 17662306a36Sopenharmony_ci iph->saddr, iph->daddr, dif, sdif)) 17762306a36Sopenharmony_ci continue; 17862306a36Sopenharmony_ci delivered = 1; 17962306a36Sopenharmony_ci if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) && 18062306a36Sopenharmony_ci ip_mc_sf_allow(sk, iph->daddr, iph->saddr, 18162306a36Sopenharmony_ci skb->dev->ifindex, sdif)) { 18262306a36Sopenharmony_ci struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* Not releasing hash table! */ 18562306a36Sopenharmony_ci if (clone) 18662306a36Sopenharmony_ci raw_rcv(sk, clone); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci rcu_read_unlock(); 19062306a36Sopenharmony_ci return delivered; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ciint raw_local_deliver(struct sk_buff *skb, int protocol) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return raw_v4_input(net, skb, ip_hdr(skb), 19862306a36Sopenharmony_ci raw_hashfunc(net, protocol)); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 20462306a36Sopenharmony_ci const int type = icmp_hdr(skb)->type; 20562306a36Sopenharmony_ci const int code = icmp_hdr(skb)->code; 20662306a36Sopenharmony_ci int harderr = 0; 20762306a36Sopenharmony_ci bool recverr; 20862306a36Sopenharmony_ci int err = 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) 21162306a36Sopenharmony_ci ipv4_sk_update_pmtu(skb, sk, info); 21262306a36Sopenharmony_ci else if (type == ICMP_REDIRECT) { 21362306a36Sopenharmony_ci ipv4_sk_redirect(skb, sk); 21462306a36Sopenharmony_ci return; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* Report error on raw socket, if: 21862306a36Sopenharmony_ci 1. User requested ip_recverr. 21962306a36Sopenharmony_ci 2. Socket is connected (otherwise the error indication 22062306a36Sopenharmony_ci is useless without ip_recverr and error is hard. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci recverr = inet_test_bit(RECVERR, sk); 22362306a36Sopenharmony_ci if (!recverr && sk->sk_state != TCP_ESTABLISHED) 22462306a36Sopenharmony_ci return; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci switch (type) { 22762306a36Sopenharmony_ci default: 22862306a36Sopenharmony_ci case ICMP_TIME_EXCEEDED: 22962306a36Sopenharmony_ci err = EHOSTUNREACH; 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci case ICMP_SOURCE_QUENCH: 23262306a36Sopenharmony_ci return; 23362306a36Sopenharmony_ci case ICMP_PARAMETERPROB: 23462306a36Sopenharmony_ci err = EPROTO; 23562306a36Sopenharmony_ci harderr = 1; 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci case ICMP_DEST_UNREACH: 23862306a36Sopenharmony_ci err = EHOSTUNREACH; 23962306a36Sopenharmony_ci if (code > NR_ICMP_UNREACH) 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci if (code == ICMP_FRAG_NEEDED) { 24262306a36Sopenharmony_ci harderr = inet->pmtudisc != IP_PMTUDISC_DONT; 24362306a36Sopenharmony_ci err = EMSGSIZE; 24462306a36Sopenharmony_ci } else { 24562306a36Sopenharmony_ci err = icmp_err_convert[code].errno; 24662306a36Sopenharmony_ci harderr = icmp_err_convert[code].fatal; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (recverr) { 25162306a36Sopenharmony_ci const struct iphdr *iph = (const struct iphdr *)skb->data; 25262306a36Sopenharmony_ci u8 *payload = skb->data + (iph->ihl << 2); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (inet_test_bit(HDRINCL, sk)) 25562306a36Sopenharmony_ci payload = skb->data; 25662306a36Sopenharmony_ci ip_icmp_error(sk, skb, err, 0, info, payload); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (recverr || harderr) { 26062306a36Sopenharmony_ci sk->sk_err = err; 26162306a36Sopenharmony_ci sk_error_report(sk); 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_civoid raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 26862306a36Sopenharmony_ci int dif = skb->dev->ifindex; 26962306a36Sopenharmony_ci int sdif = inet_sdif(skb); 27062306a36Sopenharmony_ci struct hlist_head *hlist; 27162306a36Sopenharmony_ci const struct iphdr *iph; 27262306a36Sopenharmony_ci struct sock *sk; 27362306a36Sopenharmony_ci int hash; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci hash = raw_hashfunc(net, protocol); 27662306a36Sopenharmony_ci hlist = &raw_v4_hashinfo.ht[hash]; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci rcu_read_lock(); 27962306a36Sopenharmony_ci sk_for_each_rcu(sk, hlist) { 28062306a36Sopenharmony_ci iph = (const struct iphdr *)skb->data; 28162306a36Sopenharmony_ci if (!raw_v4_match(net, sk, iph->protocol, 28262306a36Sopenharmony_ci iph->daddr, iph->saddr, dif, sdif)) 28362306a36Sopenharmony_ci continue; 28462306a36Sopenharmony_ci raw_err(sk, skb, info); 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci rcu_read_unlock(); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci enum skb_drop_reason reason; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* Charge it to the socket. */ 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci ipv4_pktinfo_prepare(sk, skb, true); 29662306a36Sopenharmony_ci if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) { 29762306a36Sopenharmony_ci kfree_skb_reason(skb, reason); 29862306a36Sopenharmony_ci return NET_RX_DROP; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return NET_RX_SUCCESS; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ciint raw_rcv(struct sock *sk, struct sk_buff *skb) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { 30762306a36Sopenharmony_ci atomic_inc(&sk->sk_drops); 30862306a36Sopenharmony_ci kfree_skb_reason(skb, SKB_DROP_REASON_XFRM_POLICY); 30962306a36Sopenharmony_ci return NET_RX_DROP; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci nf_reset_ct(skb); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci skb_push(skb, skb->data - skb_network_header(skb)); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci raw_rcv_skb(sk, skb); 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, 32062306a36Sopenharmony_ci struct msghdr *msg, size_t length, 32162306a36Sopenharmony_ci struct rtable **rtp, unsigned int flags, 32262306a36Sopenharmony_ci const struct sockcm_cookie *sockc) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 32562306a36Sopenharmony_ci struct net *net = sock_net(sk); 32662306a36Sopenharmony_ci struct iphdr *iph; 32762306a36Sopenharmony_ci struct sk_buff *skb; 32862306a36Sopenharmony_ci unsigned int iphlen; 32962306a36Sopenharmony_ci int err; 33062306a36Sopenharmony_ci struct rtable *rt = *rtp; 33162306a36Sopenharmony_ci int hlen, tlen; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (length > rt->dst.dev->mtu) { 33462306a36Sopenharmony_ci ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, 33562306a36Sopenharmony_ci rt->dst.dev->mtu); 33662306a36Sopenharmony_ci return -EMSGSIZE; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci if (length < sizeof(struct iphdr)) 33962306a36Sopenharmony_ci return -EINVAL; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (flags&MSG_PROBE) 34262306a36Sopenharmony_ci goto out; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci hlen = LL_RESERVED_SPACE(rt->dst.dev); 34562306a36Sopenharmony_ci tlen = rt->dst.dev->needed_tailroom; 34662306a36Sopenharmony_ci skb = sock_alloc_send_skb(sk, 34762306a36Sopenharmony_ci length + hlen + tlen + 15, 34862306a36Sopenharmony_ci flags & MSG_DONTWAIT, &err); 34962306a36Sopenharmony_ci if (!skb) 35062306a36Sopenharmony_ci goto error; 35162306a36Sopenharmony_ci skb_reserve(skb, hlen); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci skb->protocol = htons(ETH_P_IP); 35462306a36Sopenharmony_ci skb->priority = READ_ONCE(sk->sk_priority); 35562306a36Sopenharmony_ci skb->mark = sockc->mark; 35662306a36Sopenharmony_ci skb->tstamp = sockc->transmit_time; 35762306a36Sopenharmony_ci skb_dst_set(skb, &rt->dst); 35862306a36Sopenharmony_ci *rtp = NULL; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci skb_reset_network_header(skb); 36162306a36Sopenharmony_ci iph = ip_hdr(skb); 36262306a36Sopenharmony_ci skb_put(skb, length); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci skb_setup_tx_timestamp(skb, sockc->tsflags); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (flags & MSG_CONFIRM) 36962306a36Sopenharmony_ci skb_set_dst_pending_confirm(skb, 1); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci skb->transport_header = skb->network_header; 37262306a36Sopenharmony_ci err = -EFAULT; 37362306a36Sopenharmony_ci if (memcpy_from_msg(iph, msg, length)) 37462306a36Sopenharmony_ci goto error_free; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci iphlen = iph->ihl * 4; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* 37962306a36Sopenharmony_ci * We don't want to modify the ip header, but we do need to 38062306a36Sopenharmony_ci * be sure that it won't cause problems later along the network 38162306a36Sopenharmony_ci * stack. Specifically we want to make sure that iph->ihl is a 38262306a36Sopenharmony_ci * sane value. If ihl points beyond the length of the buffer passed 38362306a36Sopenharmony_ci * in, reject the frame as invalid 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_ci err = -EINVAL; 38662306a36Sopenharmony_ci if (iphlen > length) 38762306a36Sopenharmony_ci goto error_free; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (iphlen >= sizeof(*iph)) { 39062306a36Sopenharmony_ci if (!iph->saddr) 39162306a36Sopenharmony_ci iph->saddr = fl4->saddr; 39262306a36Sopenharmony_ci iph->check = 0; 39362306a36Sopenharmony_ci iph->tot_len = htons(length); 39462306a36Sopenharmony_ci if (!iph->id) 39562306a36Sopenharmony_ci ip_select_ident(net, skb, NULL); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 39862306a36Sopenharmony_ci skb->transport_header += iphlen; 39962306a36Sopenharmony_ci if (iph->protocol == IPPROTO_ICMP && 40062306a36Sopenharmony_ci length >= iphlen + sizeof(struct icmphdr)) 40162306a36Sopenharmony_ci icmp_out_count(net, ((struct icmphdr *) 40262306a36Sopenharmony_ci skb_transport_header(skb))->type); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, 40662306a36Sopenharmony_ci net, sk, skb, NULL, rt->dst.dev, 40762306a36Sopenharmony_ci dst_output); 40862306a36Sopenharmony_ci if (err > 0) 40962306a36Sopenharmony_ci err = net_xmit_errno(err); 41062306a36Sopenharmony_ci if (err) 41162306a36Sopenharmony_ci goto error; 41262306a36Sopenharmony_ciout: 41362306a36Sopenharmony_ci return 0; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cierror_free: 41662306a36Sopenharmony_ci kfree_skb(skb); 41762306a36Sopenharmony_cierror: 41862306a36Sopenharmony_ci IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); 41962306a36Sopenharmony_ci if (err == -ENOBUFS && !inet_test_bit(RECVERR, sk)) 42062306a36Sopenharmony_ci err = 0; 42162306a36Sopenharmony_ci return err; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci int err; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (fl4->flowi4_proto != IPPROTO_ICMP) 42962306a36Sopenharmony_ci return 0; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* We only need the first two bytes. */ 43262306a36Sopenharmony_ci rfv->hlen = 2; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci err = memcpy_from_msg(rfv->hdr.c, rfv->msg, rfv->hlen); 43562306a36Sopenharmony_ci if (err) 43662306a36Sopenharmony_ci return err; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci fl4->fl4_icmp_type = rfv->hdr.icmph.type; 43962306a36Sopenharmony_ci fl4->fl4_icmp_code = rfv->hdr.icmph.code; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic int raw_getfrag(void *from, char *to, int offset, int len, int odd, 44562306a36Sopenharmony_ci struct sk_buff *skb) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct raw_frag_vec *rfv = from; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (offset < rfv->hlen) { 45062306a36Sopenharmony_ci int copy = min(rfv->hlen - offset, len); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) 45362306a36Sopenharmony_ci memcpy(to, rfv->hdr.c + offset, copy); 45462306a36Sopenharmony_ci else 45562306a36Sopenharmony_ci skb->csum = csum_block_add( 45662306a36Sopenharmony_ci skb->csum, 45762306a36Sopenharmony_ci csum_partial_copy_nocheck(rfv->hdr.c + offset, 45862306a36Sopenharmony_ci to, copy), 45962306a36Sopenharmony_ci odd); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci odd = 0; 46262306a36Sopenharmony_ci offset += copy; 46362306a36Sopenharmony_ci to += copy; 46462306a36Sopenharmony_ci len -= copy; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (!len) 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci offset -= rfv->hlen; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return ip_generic_getfrag(rfv->msg, to, offset, len, odd, skb); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 47862306a36Sopenharmony_ci struct net *net = sock_net(sk); 47962306a36Sopenharmony_ci struct ipcm_cookie ipc; 48062306a36Sopenharmony_ci struct rtable *rt = NULL; 48162306a36Sopenharmony_ci struct flowi4 fl4; 48262306a36Sopenharmony_ci u8 tos, scope; 48362306a36Sopenharmony_ci int free = 0; 48462306a36Sopenharmony_ci __be32 daddr; 48562306a36Sopenharmony_ci __be32 saddr; 48662306a36Sopenharmony_ci int err; 48762306a36Sopenharmony_ci struct ip_options_data opt_copy; 48862306a36Sopenharmony_ci struct raw_frag_vec rfv; 48962306a36Sopenharmony_ci int hdrincl; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci err = -EMSGSIZE; 49262306a36Sopenharmony_ci if (len > 0xFFFF) 49362306a36Sopenharmony_ci goto out; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci hdrincl = inet_test_bit(HDRINCL, sk); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * Check the flags. 49962306a36Sopenharmony_ci */ 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci err = -EOPNOTSUPP; 50262306a36Sopenharmony_ci if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message */ 50362306a36Sopenharmony_ci goto out; /* compatibility */ 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * Get and verify the address. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (msg->msg_namelen) { 51062306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); 51162306a36Sopenharmony_ci err = -EINVAL; 51262306a36Sopenharmony_ci if (msg->msg_namelen < sizeof(*usin)) 51362306a36Sopenharmony_ci goto out; 51462306a36Sopenharmony_ci if (usin->sin_family != AF_INET) { 51562306a36Sopenharmony_ci pr_info_once("%s: %s forgot to set AF_INET. Fix it!\n", 51662306a36Sopenharmony_ci __func__, current->comm); 51762306a36Sopenharmony_ci err = -EAFNOSUPPORT; 51862306a36Sopenharmony_ci if (usin->sin_family) 51962306a36Sopenharmony_ci goto out; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci daddr = usin->sin_addr.s_addr; 52262306a36Sopenharmony_ci /* ANK: I did not forget to get protocol from port field. 52362306a36Sopenharmony_ci * I just do not know, who uses this weirdness. 52462306a36Sopenharmony_ci * IP_HDRINCL is much more convenient. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ci } else { 52762306a36Sopenharmony_ci err = -EDESTADDRREQ; 52862306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) 52962306a36Sopenharmony_ci goto out; 53062306a36Sopenharmony_ci daddr = inet->inet_daddr; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci ipcm_init_sk(&ipc, inet); 53462306a36Sopenharmony_ci /* Keep backward compat */ 53562306a36Sopenharmony_ci if (hdrincl) 53662306a36Sopenharmony_ci ipc.protocol = IPPROTO_RAW; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (msg->msg_controllen) { 53962306a36Sopenharmony_ci err = ip_cmsg_send(sk, msg, &ipc, false); 54062306a36Sopenharmony_ci if (unlikely(err)) { 54162306a36Sopenharmony_ci kfree(ipc.opt); 54262306a36Sopenharmony_ci goto out; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci if (ipc.opt) 54562306a36Sopenharmony_ci free = 1; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci saddr = ipc.addr; 54962306a36Sopenharmony_ci ipc.addr = daddr; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (!ipc.opt) { 55262306a36Sopenharmony_ci struct ip_options_rcu *inet_opt; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci rcu_read_lock(); 55562306a36Sopenharmony_ci inet_opt = rcu_dereference(inet->inet_opt); 55662306a36Sopenharmony_ci if (inet_opt) { 55762306a36Sopenharmony_ci memcpy(&opt_copy, inet_opt, 55862306a36Sopenharmony_ci sizeof(*inet_opt) + inet_opt->opt.optlen); 55962306a36Sopenharmony_ci ipc.opt = &opt_copy.opt; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci rcu_read_unlock(); 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (ipc.opt) { 56562306a36Sopenharmony_ci err = -EINVAL; 56662306a36Sopenharmony_ci /* Linux does not mangle headers on raw sockets, 56762306a36Sopenharmony_ci * so that IP options + IP_HDRINCL is non-sense. 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_ci if (hdrincl) 57062306a36Sopenharmony_ci goto done; 57162306a36Sopenharmony_ci if (ipc.opt->opt.srr) { 57262306a36Sopenharmony_ci if (!daddr) 57362306a36Sopenharmony_ci goto done; 57462306a36Sopenharmony_ci daddr = ipc.opt->opt.faddr; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci tos = get_rttos(&ipc, inet); 57862306a36Sopenharmony_ci scope = ip_sendmsg_scope(inet, &ipc, msg); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (ipv4_is_multicast(daddr)) { 58162306a36Sopenharmony_ci if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif)) 58262306a36Sopenharmony_ci ipc.oif = inet->mc_index; 58362306a36Sopenharmony_ci if (!saddr) 58462306a36Sopenharmony_ci saddr = inet->mc_addr; 58562306a36Sopenharmony_ci } else if (!ipc.oif) { 58662306a36Sopenharmony_ci ipc.oif = inet->uc_index; 58762306a36Sopenharmony_ci } else if (ipv4_is_lbcast(daddr) && inet->uc_index) { 58862306a36Sopenharmony_ci /* oif is set, packet is to local broadcast 58962306a36Sopenharmony_ci * and uc_index is set. oif is most likely set 59062306a36Sopenharmony_ci * by sk_bound_dev_if. If uc_index != oif check if the 59162306a36Sopenharmony_ci * oif is an L3 master and uc_index is an L3 slave. 59262306a36Sopenharmony_ci * If so, we want to allow the send using the uc_index. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci if (ipc.oif != inet->uc_index && 59562306a36Sopenharmony_ci ipc.oif == l3mdev_master_ifindex_by_index(sock_net(sk), 59662306a36Sopenharmony_ci inet->uc_index)) { 59762306a36Sopenharmony_ci ipc.oif = inet->uc_index; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos, scope, 60262306a36Sopenharmony_ci hdrincl ? ipc.protocol : sk->sk_protocol, 60362306a36Sopenharmony_ci inet_sk_flowi_flags(sk) | 60462306a36Sopenharmony_ci (hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), 60562306a36Sopenharmony_ci daddr, saddr, 0, 0, sk->sk_uid); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (!hdrincl) { 60862306a36Sopenharmony_ci rfv.msg = msg; 60962306a36Sopenharmony_ci rfv.hlen = 0; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci err = raw_probe_proto_opt(&rfv, &fl4); 61262306a36Sopenharmony_ci if (err) 61362306a36Sopenharmony_ci goto done; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci security_sk_classify_flow(sk, flowi4_to_flowi_common(&fl4)); 61762306a36Sopenharmony_ci rt = ip_route_output_flow(net, &fl4, sk); 61862306a36Sopenharmony_ci if (IS_ERR(rt)) { 61962306a36Sopenharmony_ci err = PTR_ERR(rt); 62062306a36Sopenharmony_ci rt = NULL; 62162306a36Sopenharmony_ci goto done; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci err = -EACCES; 62562306a36Sopenharmony_ci if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST)) 62662306a36Sopenharmony_ci goto done; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (msg->msg_flags & MSG_CONFIRM) 62962306a36Sopenharmony_ci goto do_confirm; 63062306a36Sopenharmony_ciback_from_confirm: 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (hdrincl) 63362306a36Sopenharmony_ci err = raw_send_hdrinc(sk, &fl4, msg, len, 63462306a36Sopenharmony_ci &rt, msg->msg_flags, &ipc.sockc); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci else { 63762306a36Sopenharmony_ci if (!ipc.addr) 63862306a36Sopenharmony_ci ipc.addr = fl4.daddr; 63962306a36Sopenharmony_ci lock_sock(sk); 64062306a36Sopenharmony_ci err = ip_append_data(sk, &fl4, raw_getfrag, 64162306a36Sopenharmony_ci &rfv, len, 0, 64262306a36Sopenharmony_ci &ipc, &rt, msg->msg_flags); 64362306a36Sopenharmony_ci if (err) 64462306a36Sopenharmony_ci ip_flush_pending_frames(sk); 64562306a36Sopenharmony_ci else if (!(msg->msg_flags & MSG_MORE)) { 64662306a36Sopenharmony_ci err = ip_push_pending_frames(sk, &fl4); 64762306a36Sopenharmony_ci if (err == -ENOBUFS && !inet_test_bit(RECVERR, sk)) 64862306a36Sopenharmony_ci err = 0; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci release_sock(sk); 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_cidone: 65362306a36Sopenharmony_ci if (free) 65462306a36Sopenharmony_ci kfree(ipc.opt); 65562306a36Sopenharmony_ci ip_rt_put(rt); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ciout: 65862306a36Sopenharmony_ci if (err < 0) 65962306a36Sopenharmony_ci return err; 66062306a36Sopenharmony_ci return len; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cido_confirm: 66362306a36Sopenharmony_ci if (msg->msg_flags & MSG_PROBE) 66462306a36Sopenharmony_ci dst_confirm_neigh(&rt->dst, &fl4.daddr); 66562306a36Sopenharmony_ci if (!(msg->msg_flags & MSG_PROBE) || len) 66662306a36Sopenharmony_ci goto back_from_confirm; 66762306a36Sopenharmony_ci err = 0; 66862306a36Sopenharmony_ci goto done; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic void raw_close(struct sock *sk, long timeout) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci /* 67462306a36Sopenharmony_ci * Raw sockets may have direct kernel references. Kill them. 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_ci ip_ra_control(sk, 0, NULL); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci sk_common_release(sk); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic void raw_destroy(struct sock *sk) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci lock_sock(sk); 68462306a36Sopenharmony_ci ip_flush_pending_frames(sk); 68562306a36Sopenharmony_ci release_sock(sk); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci/* This gets rid of all the nasties in af_inet. -DaveM */ 68962306a36Sopenharmony_cistatic int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 69262306a36Sopenharmony_ci struct sockaddr_in *addr = (struct sockaddr_in *) uaddr; 69362306a36Sopenharmony_ci struct net *net = sock_net(sk); 69462306a36Sopenharmony_ci u32 tb_id = RT_TABLE_LOCAL; 69562306a36Sopenharmony_ci int ret = -EINVAL; 69662306a36Sopenharmony_ci int chk_addr_ret; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci lock_sock(sk); 69962306a36Sopenharmony_ci if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) 70062306a36Sopenharmony_ci goto out; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (sk->sk_bound_dev_if) 70362306a36Sopenharmony_ci tb_id = l3mdev_fib_table_by_index(net, 70462306a36Sopenharmony_ci sk->sk_bound_dev_if) ? : tb_id; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci ret = -EADDRNOTAVAIL; 70962306a36Sopenharmony_ci if (!inet_addr_valid_or_nonlocal(net, inet, addr->sin_addr.s_addr, 71062306a36Sopenharmony_ci chk_addr_ret)) 71162306a36Sopenharmony_ci goto out; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr; 71462306a36Sopenharmony_ci if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) 71562306a36Sopenharmony_ci inet->inet_saddr = 0; /* Use device */ 71662306a36Sopenharmony_ci sk_dst_reset(sk); 71762306a36Sopenharmony_ci ret = 0; 71862306a36Sopenharmony_ciout: 71962306a36Sopenharmony_ci release_sock(sk); 72062306a36Sopenharmony_ci return ret; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci/* 72462306a36Sopenharmony_ci * This should be easy, if there is something there 72562306a36Sopenharmony_ci * we return it, otherwise we block. 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, 72962306a36Sopenharmony_ci int flags, int *addr_len) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 73262306a36Sopenharmony_ci size_t copied = 0; 73362306a36Sopenharmony_ci int err = -EOPNOTSUPP; 73462306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); 73562306a36Sopenharmony_ci struct sk_buff *skb; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (flags & MSG_OOB) 73862306a36Sopenharmony_ci goto out; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (flags & MSG_ERRQUEUE) { 74162306a36Sopenharmony_ci err = ip_recv_error(sk, msg, len, addr_len); 74262306a36Sopenharmony_ci goto out; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci skb = skb_recv_datagram(sk, flags, &err); 74662306a36Sopenharmony_ci if (!skb) 74762306a36Sopenharmony_ci goto out; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci copied = skb->len; 75062306a36Sopenharmony_ci if (len < copied) { 75162306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 75262306a36Sopenharmony_ci copied = len; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci err = skb_copy_datagram_msg(skb, 0, msg, copied); 75662306a36Sopenharmony_ci if (err) 75762306a36Sopenharmony_ci goto done; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci sock_recv_cmsgs(msg, sk, skb); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* Copy the address. */ 76262306a36Sopenharmony_ci if (sin) { 76362306a36Sopenharmony_ci sin->sin_family = AF_INET; 76462306a36Sopenharmony_ci sin->sin_addr.s_addr = ip_hdr(skb)->saddr; 76562306a36Sopenharmony_ci sin->sin_port = 0; 76662306a36Sopenharmony_ci memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); 76762306a36Sopenharmony_ci *addr_len = sizeof(*sin); 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci if (inet_cmsg_flags(inet)) 77062306a36Sopenharmony_ci ip_cmsg_recv(msg, skb); 77162306a36Sopenharmony_ci if (flags & MSG_TRUNC) 77262306a36Sopenharmony_ci copied = skb->len; 77362306a36Sopenharmony_cidone: 77462306a36Sopenharmony_ci skb_free_datagram(sk, skb); 77562306a36Sopenharmony_ciout: 77662306a36Sopenharmony_ci if (err) 77762306a36Sopenharmony_ci return err; 77862306a36Sopenharmony_ci return copied; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic int raw_sk_init(struct sock *sk) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci struct raw_sock *rp = raw_sk(sk); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (inet_sk(sk)->inet_num == IPPROTO_ICMP) 78662306a36Sopenharmony_ci memset(&rp->filter, 0, sizeof(rp->filter)); 78762306a36Sopenharmony_ci return 0; 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic int raw_seticmpfilter(struct sock *sk, sockptr_t optval, int optlen) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci if (optlen > sizeof(struct icmp_filter)) 79362306a36Sopenharmony_ci optlen = sizeof(struct icmp_filter); 79462306a36Sopenharmony_ci if (copy_from_sockptr(&raw_sk(sk)->filter, optval, optlen)) 79562306a36Sopenharmony_ci return -EFAULT; 79662306a36Sopenharmony_ci return 0; 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *optlen) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci int len, ret = -EFAULT; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (get_user(len, optlen)) 80462306a36Sopenharmony_ci goto out; 80562306a36Sopenharmony_ci ret = -EINVAL; 80662306a36Sopenharmony_ci if (len < 0) 80762306a36Sopenharmony_ci goto out; 80862306a36Sopenharmony_ci if (len > sizeof(struct icmp_filter)) 80962306a36Sopenharmony_ci len = sizeof(struct icmp_filter); 81062306a36Sopenharmony_ci ret = -EFAULT; 81162306a36Sopenharmony_ci if (put_user(len, optlen) || 81262306a36Sopenharmony_ci copy_to_user(optval, &raw_sk(sk)->filter, len)) 81362306a36Sopenharmony_ci goto out; 81462306a36Sopenharmony_ci ret = 0; 81562306a36Sopenharmony_ciout: return ret; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic int do_raw_setsockopt(struct sock *sk, int level, int optname, 81962306a36Sopenharmony_ci sockptr_t optval, unsigned int optlen) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci if (optname == ICMP_FILTER) { 82262306a36Sopenharmony_ci if (inet_sk(sk)->inet_num != IPPROTO_ICMP) 82362306a36Sopenharmony_ci return -EOPNOTSUPP; 82462306a36Sopenharmony_ci else 82562306a36Sopenharmony_ci return raw_seticmpfilter(sk, optval, optlen); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci return -ENOPROTOOPT; 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic int raw_setsockopt(struct sock *sk, int level, int optname, 83162306a36Sopenharmony_ci sockptr_t optval, unsigned int optlen) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci if (level != SOL_RAW) 83462306a36Sopenharmony_ci return ip_setsockopt(sk, level, optname, optval, optlen); 83562306a36Sopenharmony_ci return do_raw_setsockopt(sk, level, optname, optval, optlen); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic int do_raw_getsockopt(struct sock *sk, int level, int optname, 83962306a36Sopenharmony_ci char __user *optval, int __user *optlen) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci if (optname == ICMP_FILTER) { 84262306a36Sopenharmony_ci if (inet_sk(sk)->inet_num != IPPROTO_ICMP) 84362306a36Sopenharmony_ci return -EOPNOTSUPP; 84462306a36Sopenharmony_ci else 84562306a36Sopenharmony_ci return raw_geticmpfilter(sk, optval, optlen); 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci return -ENOPROTOOPT; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int raw_getsockopt(struct sock *sk, int level, int optname, 85162306a36Sopenharmony_ci char __user *optval, int __user *optlen) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci if (level != SOL_RAW) 85462306a36Sopenharmony_ci return ip_getsockopt(sk, level, optname, optval, optlen); 85562306a36Sopenharmony_ci return do_raw_getsockopt(sk, level, optname, optval, optlen); 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic int raw_ioctl(struct sock *sk, int cmd, int *karg) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci switch (cmd) { 86162306a36Sopenharmony_ci case SIOCOUTQ: { 86262306a36Sopenharmony_ci *karg = sk_wmem_alloc_get(sk); 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci case SIOCINQ: { 86662306a36Sopenharmony_ci struct sk_buff *skb; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci spin_lock_bh(&sk->sk_receive_queue.lock); 86962306a36Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 87062306a36Sopenharmony_ci if (skb) 87162306a36Sopenharmony_ci *karg = skb->len; 87262306a36Sopenharmony_ci else 87362306a36Sopenharmony_ci *karg = 0; 87462306a36Sopenharmony_ci spin_unlock_bh(&sk->sk_receive_queue.lock); 87562306a36Sopenharmony_ci return 0; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci default: 87962306a36Sopenharmony_ci#ifdef CONFIG_IP_MROUTE 88062306a36Sopenharmony_ci return ipmr_ioctl(sk, cmd, karg); 88162306a36Sopenharmony_ci#else 88262306a36Sopenharmony_ci return -ENOIOCTLCMD; 88362306a36Sopenharmony_ci#endif 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 88862306a36Sopenharmony_cistatic int compat_raw_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci switch (cmd) { 89162306a36Sopenharmony_ci case SIOCOUTQ: 89262306a36Sopenharmony_ci case SIOCINQ: 89362306a36Sopenharmony_ci return -ENOIOCTLCMD; 89462306a36Sopenharmony_ci default: 89562306a36Sopenharmony_ci#ifdef CONFIG_IP_MROUTE 89662306a36Sopenharmony_ci return ipmr_compat_ioctl(sk, cmd, compat_ptr(arg)); 89762306a36Sopenharmony_ci#else 89862306a36Sopenharmony_ci return -ENOIOCTLCMD; 89962306a36Sopenharmony_ci#endif 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci#endif 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ciint raw_abort(struct sock *sk, int err) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci lock_sock(sk); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci sk->sk_err = err; 90962306a36Sopenharmony_ci sk_error_report(sk); 91062306a36Sopenharmony_ci __udp_disconnect(sk, 0); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci release_sock(sk); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci return 0; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(raw_abort); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cistruct proto raw_prot = { 91962306a36Sopenharmony_ci .name = "RAW", 92062306a36Sopenharmony_ci .owner = THIS_MODULE, 92162306a36Sopenharmony_ci .close = raw_close, 92262306a36Sopenharmony_ci .destroy = raw_destroy, 92362306a36Sopenharmony_ci .connect = ip4_datagram_connect, 92462306a36Sopenharmony_ci .disconnect = __udp_disconnect, 92562306a36Sopenharmony_ci .ioctl = raw_ioctl, 92662306a36Sopenharmony_ci .init = raw_sk_init, 92762306a36Sopenharmony_ci .setsockopt = raw_setsockopt, 92862306a36Sopenharmony_ci .getsockopt = raw_getsockopt, 92962306a36Sopenharmony_ci .sendmsg = raw_sendmsg, 93062306a36Sopenharmony_ci .recvmsg = raw_recvmsg, 93162306a36Sopenharmony_ci .bind = raw_bind, 93262306a36Sopenharmony_ci .backlog_rcv = raw_rcv_skb, 93362306a36Sopenharmony_ci .release_cb = ip4_datagram_release_cb, 93462306a36Sopenharmony_ci .hash = raw_hash_sk, 93562306a36Sopenharmony_ci .unhash = raw_unhash_sk, 93662306a36Sopenharmony_ci .obj_size = sizeof(struct raw_sock), 93762306a36Sopenharmony_ci .useroffset = offsetof(struct raw_sock, filter), 93862306a36Sopenharmony_ci .usersize = sizeof_field(struct raw_sock, filter), 93962306a36Sopenharmony_ci .h.raw_hash = &raw_v4_hashinfo, 94062306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 94162306a36Sopenharmony_ci .compat_ioctl = compat_raw_ioctl, 94262306a36Sopenharmony_ci#endif 94362306a36Sopenharmony_ci .diag_destroy = raw_abort, 94462306a36Sopenharmony_ci}; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 94762306a36Sopenharmony_cistatic struct sock *raw_get_first(struct seq_file *seq, int bucket) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci struct raw_hashinfo *h = pde_data(file_inode(seq->file)); 95062306a36Sopenharmony_ci struct raw_iter_state *state = raw_seq_private(seq); 95162306a36Sopenharmony_ci struct hlist_head *hlist; 95262306a36Sopenharmony_ci struct sock *sk; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci for (state->bucket = bucket; state->bucket < RAW_HTABLE_SIZE; 95562306a36Sopenharmony_ci ++state->bucket) { 95662306a36Sopenharmony_ci hlist = &h->ht[state->bucket]; 95762306a36Sopenharmony_ci sk_for_each(sk, hlist) { 95862306a36Sopenharmony_ci if (sock_net(sk) == seq_file_net(seq)) 95962306a36Sopenharmony_ci return sk; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci return NULL; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic struct sock *raw_get_next(struct seq_file *seq, struct sock *sk) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci struct raw_iter_state *state = raw_seq_private(seq); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci do { 97062306a36Sopenharmony_ci sk = sk_next(sk); 97162306a36Sopenharmony_ci } while (sk && sock_net(sk) != seq_file_net(seq)); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (!sk) 97462306a36Sopenharmony_ci return raw_get_first(seq, state->bucket + 1); 97562306a36Sopenharmony_ci return sk; 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_cistatic struct sock *raw_get_idx(struct seq_file *seq, loff_t pos) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci struct sock *sk = raw_get_first(seq, 0); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci if (sk) 98362306a36Sopenharmony_ci while (pos && (sk = raw_get_next(seq, sk)) != NULL) 98462306a36Sopenharmony_ci --pos; 98562306a36Sopenharmony_ci return pos ? NULL : sk; 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_civoid *raw_seq_start(struct seq_file *seq, loff_t *pos) 98962306a36Sopenharmony_ci __acquires(&h->lock) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci struct raw_hashinfo *h = pde_data(file_inode(seq->file)); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci spin_lock(&h->lock); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci return *pos ? raw_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(raw_seq_start); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_civoid *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci struct sock *sk; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) 100462306a36Sopenharmony_ci sk = raw_get_first(seq, 0); 100562306a36Sopenharmony_ci else 100662306a36Sopenharmony_ci sk = raw_get_next(seq, v); 100762306a36Sopenharmony_ci ++*pos; 100862306a36Sopenharmony_ci return sk; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(raw_seq_next); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_civoid raw_seq_stop(struct seq_file *seq, void *v) 101362306a36Sopenharmony_ci __releases(&h->lock) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci struct raw_hashinfo *h = pde_data(file_inode(seq->file)); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci spin_unlock(&h->lock); 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(raw_seq_stop); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sp); 102462306a36Sopenharmony_ci __be32 dest = inet->inet_daddr, 102562306a36Sopenharmony_ci src = inet->inet_rcv_saddr; 102662306a36Sopenharmony_ci __u16 destp = 0, 102762306a36Sopenharmony_ci srcp = inet->inet_num; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci seq_printf(seq, "%4d: %08X:%04X %08X:%04X" 103062306a36Sopenharmony_ci " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %u\n", 103162306a36Sopenharmony_ci i, src, srcp, dest, destp, sp->sk_state, 103262306a36Sopenharmony_ci sk_wmem_alloc_get(sp), 103362306a36Sopenharmony_ci sk_rmem_alloc_get(sp), 103462306a36Sopenharmony_ci 0, 0L, 0, 103562306a36Sopenharmony_ci from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)), 103662306a36Sopenharmony_ci 0, sock_i_ino(sp), 103762306a36Sopenharmony_ci refcount_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops)); 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic int raw_seq_show(struct seq_file *seq, void *v) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) 104362306a36Sopenharmony_ci seq_printf(seq, " sl local_address rem_address st tx_queue " 104462306a36Sopenharmony_ci "rx_queue tr tm->when retrnsmt uid timeout " 104562306a36Sopenharmony_ci "inode ref pointer drops\n"); 104662306a36Sopenharmony_ci else 104762306a36Sopenharmony_ci raw_sock_seq_show(seq, v, raw_seq_private(seq)->bucket); 104862306a36Sopenharmony_ci return 0; 104962306a36Sopenharmony_ci} 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_cistatic const struct seq_operations raw_seq_ops = { 105262306a36Sopenharmony_ci .start = raw_seq_start, 105362306a36Sopenharmony_ci .next = raw_seq_next, 105462306a36Sopenharmony_ci .stop = raw_seq_stop, 105562306a36Sopenharmony_ci .show = raw_seq_show, 105662306a36Sopenharmony_ci}; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic __net_init int raw_init_net(struct net *net) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci if (!proc_create_net_data("raw", 0444, net->proc_net, &raw_seq_ops, 106162306a36Sopenharmony_ci sizeof(struct raw_iter_state), &raw_v4_hashinfo)) 106262306a36Sopenharmony_ci return -ENOMEM; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci return 0; 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic __net_exit void raw_exit_net(struct net *net) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci remove_proc_entry("raw", net->proc_net); 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cistatic __net_initdata struct pernet_operations raw_net_ops = { 107362306a36Sopenharmony_ci .init = raw_init_net, 107462306a36Sopenharmony_ci .exit = raw_exit_net, 107562306a36Sopenharmony_ci}; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ciint __init raw_proc_init(void) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci return register_pernet_subsys(&raw_net_ops); 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_civoid __init raw_proc_exit(void) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci unregister_pernet_subsys(&raw_net_ops); 108662306a36Sopenharmony_ci} 108762306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cistatic void raw_sysctl_init_net(struct net *net) 109062306a36Sopenharmony_ci{ 109162306a36Sopenharmony_ci#ifdef CONFIG_NET_L3_MASTER_DEV 109262306a36Sopenharmony_ci net->ipv4.sysctl_raw_l3mdev_accept = 1; 109362306a36Sopenharmony_ci#endif 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic int __net_init raw_sysctl_init(struct net *net) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci raw_sysctl_init_net(net); 109962306a36Sopenharmony_ci return 0; 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_cistatic struct pernet_operations __net_initdata raw_sysctl_ops = { 110362306a36Sopenharmony_ci .init = raw_sysctl_init, 110462306a36Sopenharmony_ci}; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_civoid __init raw_init(void) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci raw_sysctl_init_net(&init_net); 110962306a36Sopenharmony_ci if (register_pernet_subsys(&raw_sysctl_ops)) 111062306a36Sopenharmony_ci panic("RAW: failed to init sysctl parameters.\n"); 111162306a36Sopenharmony_ci} 1112