⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipv4.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (dst == NULL)		return;	skb = dccp_ctl_make_reset(dccp_v4_ctl_socket, rxskb);	if (skb == NULL)		goto out;	rxiph = ip_hdr(rxskb);	dccp_hdr(skb)->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr,								 rxiph->daddr);	skb->dst = dst_clone(dst);	bh_lock_sock(dccp_v4_ctl_socket->sk);	err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk,				    rxiph->daddr, rxiph->saddr, NULL);	bh_unlock_sock(dccp_v4_ctl_socket->sk);	if (net_xmit_eval(err) == 0) {		DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);		DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);	}out:	 dst_release(dst);}static void dccp_v4_reqsk_destructor(struct request_sock *req){	kfree(inet_rsk(req)->opt);}static struct request_sock_ops dccp_request_sock_ops __read_mostly = {	.family		= PF_INET,	.obj_size	= sizeof(struct dccp_request_sock),	.rtx_syn_ack	= dccp_v4_send_response,	.send_ack	= dccp_reqsk_send_ack,	.destructor	= dccp_v4_reqsk_destructor,	.send_reset	= dccp_v4_ctl_send_reset,};int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb){	struct inet_request_sock *ireq;	struct request_sock *req;	struct dccp_request_sock *dreq;	const __be32 service = dccp_hdr_request(skb)->dccph_req_service;	struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);	/* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */	if (((struct rtable *)skb->dst)->rt_flags &	    (RTCF_BROADCAST | RTCF_MULTICAST))		return 0;	/* discard, don't send a reset here */	if (dccp_bad_service_code(sk, service)) {		dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;		goto drop;	}	/*	 * TW buckets are converted to open requests without	 * limitations, they conserve resources and peer is	 * evidently real one.	 */	dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;	if (inet_csk_reqsk_queue_is_full(sk))		goto drop;	/*	 * Accept backlog is full. If we have already queued enough	 * of warm entries in syn queue, drop request. It is better than	 * clogging syn queue with openreqs with exponentially increasing	 * timeout.	 */	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)		goto drop;	req = reqsk_alloc(&dccp_request_sock_ops);	if (req == NULL)		goto drop;	if (dccp_parse_options(sk, skb))		goto drop_and_free;	dccp_reqsk_init(req, skb);	if (security_inet_conn_request(sk, skb, req))		goto drop_and_free;	ireq = inet_rsk(req);	ireq->loc_addr = ip_hdr(skb)->daddr;	ireq->rmt_addr = ip_hdr(skb)->saddr;	ireq->opt	= NULL;	/*	 * Step 3: Process LISTEN state	 *	 * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie	 *	 * In fact we defer setting S.GSR, S.SWL, S.SWH to	 * dccp_create_openreq_child.	 */	dreq = dccp_rsk(req);	dreq->dreq_isr	   = dcb->dccpd_seq;	dreq->dreq_iss	   = dccp_v4_init_sequence(skb);	dreq->dreq_service = service;	if (dccp_v4_send_response(sk, req, NULL))		goto drop_and_free;	inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);	return 0;drop_and_free:	reqsk_free(req);drop:	DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);	return -1;}EXPORT_SYMBOL_GPL(dccp_v4_conn_request);int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb){	struct dccp_hdr *dh = dccp_hdr(skb);	if (sk->sk_state == DCCP_OPEN) { /* Fast path */		if (dccp_rcv_established(sk, skb, dh, skb->len))			goto reset;		return 0;	}	/*	 *  Step 3: Process LISTEN state	 *	 If P.type == Request or P contains a valid Init Cookie option,	 *	      (* Must scan the packet's options to check for Init	 *		 Cookies.  Only Init Cookies are processed here,	 *		 however; other options are processed in Step 8.  This	 *		 scan need only be performed if the endpoint uses Init	 *		 Cookies *)	 *	      (* Generate a new socket and switch to that socket *)	 *	      Set S := new socket for this port pair	 *	      S.state = RESPOND	 *	      Choose S.ISS (initial seqno) or set from Init Cookies	 *	      Initialize S.GAR := S.ISS	 *	      Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies	 *	      Continue with S.state == RESPOND	 *	      (* A Response packet will be generated in Step 11 *)	 *	 Otherwise,	 *	      Generate Reset(No Connection) unless P.type == Reset	 *	      Drop packet and return	 *	 * NOTE: the check for the packet types is done in	 *	 dccp_rcv_state_process	 */	if (sk->sk_state == DCCP_LISTEN) {		struct sock *nsk = dccp_v4_hnd_req(sk, skb);		if (nsk == NULL)			goto discard;		if (nsk != sk) {			if (dccp_child_process(sk, nsk, skb))				goto reset;			return 0;		}	}	if (dccp_rcv_state_process(sk, skb, dh, skb->len))		goto reset;	return 0;reset:	dccp_v4_ctl_send_reset(sk, skb);discard:	kfree_skb(skb);	return 0;}EXPORT_SYMBOL_GPL(dccp_v4_do_rcv);/** *	dccp_invalid_packet  -  check for malformed packets *	Implements RFC 4340, 8.5:  Step 1: Check header basics *	Packets that fail these checks are ignored and do not receive Resets. */int dccp_invalid_packet(struct sk_buff *skb){	const struct dccp_hdr *dh;	unsigned int cscov;	if (skb->pkt_type != PACKET_HOST)		return 1;	/* If the packet is shorter than 12 bytes, drop packet and return */	if (!pskb_may_pull(skb, sizeof(struct dccp_hdr))) {		DCCP_WARN("pskb_may_pull failed\n");		return 1;	}	dh = dccp_hdr(skb);	/* If P.type is not understood, drop packet and return */	if (dh->dccph_type >= DCCP_PKT_INVALID) {		DCCP_WARN("invalid packet type\n");		return 1;	}	/*	 * If P.Data Offset is too small for packet type, drop packet and return	 */	if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) {		DCCP_WARN("P.Data Offset(%u) too small\n", dh->dccph_doff);		return 1;	}	/*	 * If P.Data Offset is too too large for packet, drop packet and return	 */	if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) {		DCCP_WARN("P.Data Offset(%u) too large\n", dh->dccph_doff);		return 1;	}	/*	 * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet	 * has short sequence numbers), drop packet and return	 */	if (dh->dccph_type >= DCCP_PKT_DATA    &&	    dh->dccph_type <= DCCP_PKT_DATAACK && dh->dccph_x == 0)  {		DCCP_WARN("P.type (%s) not Data || [Data]Ack, while P.X == 0\n",			  dccp_packet_name(dh->dccph_type));		return 1;	}	/*	 * If P.CsCov is too large for the packet size, drop packet and return.	 * This must come _before_ checksumming (not as RFC 4340 suggests).	 */	cscov = dccp_csum_coverage(skb);	if (cscov > skb->len) {		DCCP_WARN("P.CsCov %u exceeds packet length %d\n",			  dh->dccph_cscov, skb->len);		return 1;	}	/* If header checksum is incorrect, drop packet and return.	 * (This step is completed in the AF-dependent functions.) */	skb->csum = skb_checksum(skb, 0, cscov, 0);	return 0;}EXPORT_SYMBOL_GPL(dccp_invalid_packet);/* this is called when real data arrives */static int dccp_v4_rcv(struct sk_buff *skb){	const struct dccp_hdr *dh;	const struct iphdr *iph;	struct sock *sk;	int min_cov;	/* Step 1: Check header basics */	if (dccp_invalid_packet(skb))		goto discard_it;	iph = ip_hdr(skb);	/* Step 1: If header checksum is incorrect, drop packet and return */	if (dccp_v4_csum_finish(skb, iph->saddr, iph->daddr)) {		DCCP_WARN("dropped packet with invalid checksum\n");		goto discard_it;	}	dh = dccp_hdr(skb);	DCCP_SKB_CB(skb)->dccpd_seq  = dccp_hdr_seq(dh);	DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;	dccp_pr_debug("%8.8s "		      "src=%u.%u.%u.%u@%-5d "		      "dst=%u.%u.%u.%u@%-5d seq=%llu",		      dccp_packet_name(dh->dccph_type),		      NIPQUAD(iph->saddr), ntohs(dh->dccph_sport),		      NIPQUAD(iph->daddr), ntohs(dh->dccph_dport),		      (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);	if (dccp_packet_without_ack(skb)) {		DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;		dccp_pr_debug_cat("\n");	} else {		DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);		dccp_pr_debug_cat(", ack=%llu\n", (unsigned long long)				  DCCP_SKB_CB(skb)->dccpd_ack_seq);	}	/* Step 2:	 *	Look up flow ID in table and get corresponding socket */	sk = __inet_lookup(&dccp_hashinfo,			   iph->saddr, dh->dccph_sport,			   iph->daddr, dh->dccph_dport, inet_iif(skb));	/*	 * Step 2:	 *	If no socket ...	 */	if (sk == NULL) {		dccp_pr_debug("failed to look up flow ID in table and "			      "get corresponding socket\n");		goto no_dccp_socket;	}	/*	 * Step 2:	 *	... or S.state == TIMEWAIT,	 *		Generate Reset(No Connection) unless P.type == Reset	 *		Drop packet and return	 */	if (sk->sk_state == DCCP_TIME_WAIT) {		dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: do_time_wait\n");		inet_twsk_put(inet_twsk(sk));		goto no_dccp_socket;	}	/*	 * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage	 *	o if MinCsCov = 0, only packets with CsCov = 0 are accepted	 *	o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov	 */	min_cov = dccp_sk(sk)->dccps_pcrlen;	if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov))  {		dccp_pr_debug("Packet CsCov %d does not satisfy MinCsCov %d\n",			      dh->dccph_cscov, min_cov);		/* FIXME: "Such packets SHOULD be reported using Data Dropped		 *         options (Section 11.7) with Drop Code 0, Protocol		 *         Constraints."                                     */		goto discard_and_relse;	}	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))		goto discard_and_relse;	nf_reset(skb);	return sk_receive_skb(sk, skb, 1);no_dccp_socket:	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))		goto discard_it;	/*	 * Step 2:	 *	If no socket ...	 *		Generate Reset(No Connection) unless P.type == Reset	 *		Drop packet and return	 */	if (dh->dccph_type != DCCP_PKT_RESET) {		DCCP_SKB_CB(skb)->dccpd_reset_code =					DCCP_RESET_CODE_NO_CONNECTION;		dccp_v4_ctl_send_reset(sk, skb);	}discard_it:	kfree_skb(skb);	return 0;discard_and_relse:	sock_put(sk);	goto discard_it;}static struct inet_connection_sock_af_ops dccp_ipv4_af_ops = {	.queue_xmit	   = ip_queue_xmit,	.send_check	   = dccp_v4_send_check,	.rebuild_header	   = inet_sk_rebuild_header,	.conn_request	   = dccp_v4_conn_request,	.syn_recv_sock	   = dccp_v4_request_recv_sock,	.net_header_len	   = sizeof(struct iphdr),	.setsockopt	   = ip_setsockopt,	.getsockopt	   = ip_getsockopt,	.addr2sockaddr	   = inet_csk_addr2sockaddr,	.sockaddr_len	   = sizeof(struct sockaddr_in),#ifdef CONFIG_COMPAT	.compat_setsockopt = compat_ip_setsockopt,	.compat_getsockopt = compat_ip_getsockopt,#endif};static int dccp_v4_init_sock(struct sock *sk){	static __u8 dccp_v4_ctl_sock_initialized;	int err = dccp_init_sock(sk, dccp_v4_ctl_sock_initialized);	if (err == 0) {		if (unlikely(!dccp_v4_ctl_sock_initialized))			dccp_v4_ctl_sock_initialized = 1;		inet_csk(sk)->icsk_af_ops = &dccp_ipv4_af_ops;	}	return err;}static struct timewait_sock_ops dccp_timewait_sock_ops = {	.twsk_obj_size	= sizeof(struct inet_timewait_sock),};DEFINE_PROTO_INUSE(dccp_v4)static struct proto dccp_v4_prot = {	.name			= "DCCP",	.owner			= THIS_MODULE,	.close			= dccp_close,	.connect		= dccp_v4_connect,	.disconnect		= dccp_disconnect,	.ioctl			= dccp_ioctl,	.init			= dccp_v4_init_sock,	.setsockopt		= dccp_setsockopt,	.getsockopt		= dccp_getsockopt,	.sendmsg		= dccp_sendmsg,	.recvmsg		= dccp_recvmsg,	.backlog_rcv		= dccp_v4_do_rcv,	.hash			= dccp_hash,	.unhash			= dccp_unhash,	.accept			= inet_csk_accept,	.get_port		= dccp_v4_get_port,	.shutdown		= dccp_shutdown,	.destroy		= dccp_destroy_sock,	.orphan_count		= &dccp_orphan_count,	.max_header		= MAX_DCCP_HEADER,	.obj_size		= sizeof(struct dccp_sock),	.rsk_prot		= &dccp_request_sock_ops,	.twsk_prot		= &dccp_timewait_sock_ops,#ifdef CONFIG_COMPAT	.compat_setsockopt	= compat_dccp_setsockopt,	.compat_getsockopt	= compat_dccp_getsockopt,#endif	REF_PROTO_INUSE(dccp_v4)};static struct net_protocol dccp_v4_protocol = {	.handler	= dccp_v4_rcv,	.err_handler	= dccp_v4_err,	.no_policy	= 1,};static const struct proto_ops inet_dccp_ops = {	.family		   = PF_INET,	.owner		   = THIS_MODULE,	.release	   = inet_release,	.bind		   = inet_bind,	.connect	   = inet_stream_connect,	.socketpair	   = sock_no_socketpair,	.accept		   = inet_accept,	.getname	   = inet_getname,	/* FIXME: work on tcp_poll to rename it to inet_csk_poll */	.poll		   = dccp_poll,	.ioctl		   = inet_ioctl,	/* FIXME: work on inet_listen to rename it to sock_common_listen */	.listen		   = inet_dccp_listen,	.shutdown	   = inet_shutdown,	.setsockopt	   = sock_common_setsockopt,	.getsockopt	   = sock_common_getsockopt,	.sendmsg	   = inet_sendmsg,	.recvmsg	   = sock_common_recvmsg,	.mmap		   = sock_no_mmap,	.sendpage	   = sock_no_sendpage,#ifdef CONFIG_COMPAT	.compat_setsockopt = compat_sock_common_setsockopt,	.compat_getsockopt = compat_sock_common_getsockopt,#endif};static struct inet_protosw dccp_v4_protosw = {	.type		= SOCK_DCCP,	.protocol	= IPPROTO_DCCP,	.prot		= &dccp_v4_prot,	.ops		= &inet_dccp_ops,	.capability	= -1,	.no_check	= 0,	.flags		= INET_PROTOSW_ICSK,};static int __init dccp_v4_init(void){	int err = proto_register(&dccp_v4_prot, 1);	if (err != 0)		goto out;	err = inet_add_protocol(&dccp_v4_protocol, IPPROTO_DCCP);	if (err != 0)		goto out_proto_unregister;	inet_register_protosw(&dccp_v4_protosw);	err = inet_csk_ctl_sock_create(&dccp_v4_ctl_socket, PF_INET,				       SOCK_DCCP, IPPROTO_DCCP);	if (err)		goto out_unregister_protosw;out:	return err;out_unregister_protosw:	inet_unregister_protosw(&dccp_v4_protosw);	inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP);out_proto_unregister:	proto_unregister(&dccp_v4_prot);	goto out;}static void __exit dccp_v4_exit(void){	inet_unregister_protosw(&dccp_v4_protosw);	inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP);	proto_unregister(&dccp_v4_prot);}module_init(dccp_v4_init);module_exit(dccp_v4_exit);/* * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33) * values directly, Also cover the case where the protocol is not specified, * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP */MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 33, 6);MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 0, 6);MODULE_LICENSE("GPL");MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -