net/ipv4/raw.c

Source file repositories/reference/linux-study-clean/net/ipv4/raw.c

File Facts

System
Linux kernel
Corpus path
net/ipv4/raw.c
Extension
.c
Size
26126 bytes
Lines
1121
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct raw_frag_vec {
	struct msghdr *msg;
	union {
		struct icmphdr icmph;
		char c[1];
	} hdr;
	int hlen;
};

struct raw_hashinfo raw_v4_hashinfo;
EXPORT_SYMBOL_GPL(raw_v4_hashinfo);

int raw_hash_sk(struct sock *sk)
{
	struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
	struct hlist_head *hlist;

	hlist = &h->ht[raw_hashfunc(sock_net(sk), inet_sk(sk)->inet_num)];

	spin_lock(&h->lock);
	sk_add_node_rcu(sk, hlist);
	sock_set_flag(sk, SOCK_RCU_FREE);
	spin_unlock(&h->lock);
	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);

	return 0;
}

void raw_unhash_sk(struct sock *sk)
{
	struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;

	spin_lock(&h->lock);
	if (sk_del_node_init_rcu(sk))
		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
	spin_unlock(&h->lock);
}

bool raw_v4_match(struct net *net, const struct sock *sk, unsigned short num,
		  __be32 raddr, __be32 laddr, int dif, int sdif)
{
	const struct inet_sock *inet = inet_sk(sk);

	if (net_eq(sock_net(sk), net) && inet->inet_num == num	&&
	    !(inet->inet_daddr && inet->inet_daddr != raddr) 	&&
	    !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
	    raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif))
		return true;
	return false;
}
EXPORT_SYMBOL_GPL(raw_v4_match);

/*
 *	0 - deliver
 *	1 - block
 */
static int icmp_filter(const struct sock *sk, const struct sk_buff *skb)
{
	struct icmphdr _hdr;
	const struct icmphdr *hdr;

	hdr = skb_header_pointer(skb, skb_transport_offset(skb),
				 sizeof(_hdr), &_hdr);
	if (!hdr)
		return 1;

	if (hdr->type < 32) {
		__u32 data = raw_sk(sk)->filter.data;

		return ((1U << hdr->type) & data) != 0;
	}

	/* Do not block unknown ICMP types */
	return 0;
}

/* IP input processing comes here for RAW socket delivery.
 * Caller owns SKB, so we must make clones.
 *
 * RFC 1122: SHOULD pass TOS value up to the transport layer.
 * -> It does. And not only TOS, but all IP header.
 */
static int raw_v4_input(struct net *net, struct sk_buff *skb,
			const struct iphdr *iph, int hash)
{
	int sdif = inet_sdif(skb);
	struct hlist_head *hlist;
	int dif = inet_iif(skb);
	int delivered = 0;
	struct sock *sk;

Annotation

Implementation Notes