net/netfilter/nf_conntrack_proto_sctp.c

Source file repositories/reference/linux-study-clean/net/netfilter/nf_conntrack_proto_sctp.c

File Facts

System
Linux kernel
Corpus path
net/netfilter/nf_conntrack_proto_sctp.c
Extension
.c
Size
22937 bytes
Lines
731
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source 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

if (sch->type == SCTP_CID_INIT) {
			struct sctp_inithdr _inithdr, *ih;
			/* Sec 8.5.1 (A) */
			if (sh->vtag)
				return false;

			ih = skb_header_pointer(skb, offset + sizeof(_sch),
						sizeof(_inithdr), &_inithdr);
			if (!ih)
				return false;

			pr_debug("Setting vtag %x for new conn\n",
				 ih->init_tag);

			ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag;
		} else if (sch->type == SCTP_CID_HEARTBEAT) {
			pr_debug("Setting vtag %x for secondary conntrack\n",
				 sh->vtag);
			ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = sh->vtag;
		} else if (sch->type == SCTP_CID_SHUTDOWN_ACK) {
		/* If it is a shutdown ack OOTB packet, we expect a return
		   shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */
			pr_debug("Setting vtag %x for new conn OOTB\n",
				 sh->vtag);
			ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag;
		}

		ct->proto.sctp.state = SCTP_CONNTRACK_NONE;
	}

	return true;
}

static bool sctp_error(struct sk_buff *skb,
		       unsigned int dataoff,
		       const struct nf_hook_state *state)
{
	const struct sctphdr *sh;
	const char *logmsg;

	if (skb->len < dataoff + sizeof(struct sctphdr)) {
		logmsg = "nf_ct_sctp: short packet ";
		goto out_invalid;
	}
	if (state->hook == NF_INET_PRE_ROUTING &&
	    state->net->ct.sysctl_checksum &&
	    skb->ip_summed == CHECKSUM_NONE) {
		if (skb_ensure_writable(skb, dataoff + sizeof(*sh))) {
			logmsg = "nf_ct_sctp: failed to read header ";
			goto out_invalid;
		}
		sh = (const struct sctphdr *)(skb->data + dataoff);
		if (sh->checksum != sctp_compute_cksum(skb, dataoff)) {
			logmsg = "nf_ct_sctp: bad CRC ";
			goto out_invalid;
		}
		skb->ip_summed = CHECKSUM_UNNECESSARY;
	}
	return false;
out_invalid:
	nf_l4proto_log_invalid(skb, state, IPPROTO_SCTP, "%s", logmsg);
	return true;
}

/* Returns verdict for packet, or -NF_ACCEPT for invalid. */
int nf_conntrack_sctp_packet(struct nf_conn *ct,
			     struct sk_buff *skb,
			     unsigned int dataoff,
			     enum ip_conntrack_info ctinfo,
			     const struct nf_hook_state *state)
{
	enum sctp_conntrack new_state, old_state;
	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
	const struct sctphdr *sh;
	struct sctphdr _sctph;
	const struct sctp_chunkhdr *sch;
	struct sctp_chunkhdr _sch;
	u_int32_t offset, count;
	unsigned int *timeouts;
	unsigned long map[256 / sizeof(unsigned long)] = { 0 };
	bool ignore = false;

	if (sctp_error(skb, dataoff, state))
		return -NF_ACCEPT;

	sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph);
	if (sh == NULL)
		goto out;

	if (do_basic_checks(ct, skb, dataoff, map, state) != 0)

Annotation

Implementation Notes