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

📄 udp.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (connected)		rt = (struct rtable*)sk_dst_check(sk, 0);	if (rt == NULL) {		err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);		if (err)			goto out;		err = -EACCES;		if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) 			goto out;		if (connected)			sk_dst_set(sk, dst_clone(&rt->u.dst));	}	if (msg->msg_flags&MSG_CONFIRM)		goto do_confirm;back_from_confirm:	ufh.saddr = rt->rt_src;	if (!ipc.addr)		ufh.daddr = ipc.addr = rt->rt_dst;	ufh.uh.len = htons(ulen);	ufh.uh.check = 0;	ufh.iov = msg->msg_iov;	ufh.wcheck = 0;	/* RFC1122: OK.  Provides the checksumming facility (MUST) as per */	/* 4.1.3.4. It's configurable by the application via setsockopt() */	/* (MAY) and it defaults to on (MUST). */	err = ip_build_xmit(sk,			    (sk->no_check == UDP_CSUM_NOXMIT ?			     udp_getfrag_nosum :			     udp_getfrag),			    &ufh, ulen, &ipc, rt, msg->msg_flags);out:	ip_rt_put(rt);	if (free)		kfree(ipc.opt);	if (!err) {		UDP_INC_STATS_USER(UdpOutDatagrams);		return len;	}	return err;do_confirm:	dst_confirm(&rt->u.dst);	if (!(msg->msg_flags&MSG_PROBE) || len)		goto back_from_confirm;	err = 0;	goto out;}/* *	IOCTL requests applicable to the UDP protocol */ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg){	switch(cmd) 	{		case SIOCOUTQ:		{			int amount = atomic_read(&sk->wmem_alloc);			return put_user(amount, (int *)arg);		}		case SIOCINQ:		{			struct sk_buff *skb;			unsigned long amount;			amount = 0;			spin_lock_irq(&sk->receive_queue.lock);			skb = skb_peek(&sk->receive_queue);			if (skb != NULL) {				/*				 * We will only return the amount				 * of this packet since that is all				 * that will be read.				 */				amount = skb->len - sizeof(struct udphdr);			}			spin_unlock_irq(&sk->receive_queue.lock);			return put_user(amount, (int *)arg);		}		default:			return -ENOIOCTLCMD;	}	return(0);}static __inline__ int __udp_checksum_complete(struct sk_buff *skb){	return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));}static __inline__ int udp_checksum_complete(struct sk_buff *skb){	return skb->ip_summed != CHECKSUM_UNNECESSARY &&		__udp_checksum_complete(skb);}/* * 	This should be easy, if there is something there we * 	return it, otherwise we block. */int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len,		int noblock, int flags, int *addr_len){  	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;  	struct sk_buff *skb;  	int copied, err;	/*	 *	Check any passed addresses	 */	if (addr_len)		*addr_len=sizeof(*sin);	if (flags & MSG_ERRQUEUE)		return ip_recv_error(sk, msg, len);	skb = skb_recv_datagram(sk, flags, noblock, &err);	if (!skb)		goto out;    	copied = skb->len - sizeof(struct udphdr);	if (copied > len) {		copied = len;		msg->msg_flags |= MSG_TRUNC;	}	if (skb->ip_summed==CHECKSUM_UNNECESSARY) {		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,					      copied);	} else if (msg->msg_flags&MSG_TRUNC) {		if (__udp_checksum_complete(skb))			goto csum_copy_err;		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,					      copied);	} else {		err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);		if (err == -EINVAL)			goto csum_copy_err;	}	if (err)		goto out_free;	sock_recv_timestamp(msg, sk, skb);	/* Copy the address. */	if (sin)	{		sin->sin_family = AF_INET;		sin->sin_port = skb->h.uh->source;		sin->sin_addr.s_addr = skb->nh.iph->saddr;		memset(sin->sin_zero, 0, sizeof(sin->sin_zero));  	}	if (sk->protinfo.af_inet.cmsg_flags)		ip_cmsg_recv(msg, skb);	err = copied;  out_free:  	skb_free_datagram(sk, skb);out:  	return err;csum_copy_err:	UDP_INC_STATS_BH(UdpInErrors);	/* Clear queue. */	if (flags&MSG_PEEK) {		int clear = 0;		spin_lock_irq(&sk->receive_queue.lock);		if (skb == skb_peek(&sk->receive_queue)) {			__skb_unlink(skb, &sk->receive_queue);			clear = 1;		}		spin_unlock_irq(&sk->receive_queue.lock);		if (clear)			kfree_skb(skb);	}	skb_free_datagram(sk, skb);	return -EAGAIN;	}int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len){	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;	struct rtable *rt;	int err;		if (addr_len < sizeof(*usin)) 	  	return -EINVAL;	if (usin->sin_family != AF_INET) 	  	return -EAFNOSUPPORT;	sk_dst_reset(sk);	err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,			       RT_CONN_FLAGS(sk), sk->bound_dev_if);	if (err)		return err;	if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) {		ip_rt_put(rt);		return -EACCES;	}  	if(!sk->saddr)	  	sk->saddr = rt->rt_src;		/* Update source address */	if(!sk->rcv_saddr)		sk->rcv_saddr = rt->rt_src;	sk->daddr = rt->rt_dst;	sk->dport = usin->sin_port;	sk->state = TCP_ESTABLISHED;	sk->protinfo.af_inet.id = jiffies;	sk_dst_set(sk, &rt->u.dst);	return(0);}int udp_disconnect(struct sock *sk, int flags){	/*	 *	1003.1g - break association.	 */	 	sk->state = TCP_CLOSE;	sk->daddr = 0;	sk->dport = 0;	sk->bound_dev_if = 0;	if (!(sk->userlocks&SOCK_BINDADDR_LOCK)) {		sk->rcv_saddr = 0;		sk->saddr = 0;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)		memset(&sk->net_pinfo.af_inet6.saddr, 0, 16);		memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, 16);#endif	}	if (!(sk->userlocks&SOCK_BINDPORT_LOCK)) {		sk->prot->unhash(sk);		sk->sport = 0;	}	sk_dst_reset(sk);	return 0;}static void udp_close(struct sock *sk, long timeout){	inet_sock_release(sk);}static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb){	/*	 *	Charge it to the socket, dropping if the queue is full.	 */#if defined(CONFIG_FILTER)	if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {		if (__udp_checksum_complete(skb)) {			UDP_INC_STATS_BH(UdpInErrors);			IP_INC_STATS_BH(IpInDiscards);			ip_statistics[smp_processor_id()*2].IpInDelivers--;			kfree_skb(skb);			return -1;		}		skb->ip_summed = CHECKSUM_UNNECESSARY;	}#endif	if (sock_queue_rcv_skb(sk,skb)<0) {		UDP_INC_STATS_BH(UdpInErrors);		IP_INC_STATS_BH(IpInDiscards);		ip_statistics[smp_processor_id()*2].IpInDelivers--;		kfree_skb(skb);		return -1;	}	UDP_INC_STATS_BH(UdpInDatagrams);	return 0;}/* *	Multicasts and broadcasts go to each listener. * *	Note: called only from the BH handler context, *	so we don't need to lock the hashes. */static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,				 u32 saddr, u32 daddr){	struct sock *sk;	int dif;	read_lock(&udp_hash_lock);	sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];	dif = skb->dev->ifindex;	sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);	if (sk) {		struct sock *sknext = NULL;		do {			struct sk_buff *skb1 = skb;			sknext = udp_v4_mcast_next(sk->next, uh->dest, daddr,						   uh->source, saddr, dif);			if(sknext)				skb1 = skb_clone(skb, GFP_ATOMIC);			if(skb1)				udp_queue_rcv_skb(sk, skb1);			sk = sknext;		} while(sknext);	} else		kfree_skb(skb);	read_unlock(&udp_hash_lock);	return 0;}/* Initialize UDP checksum. If exited with zero value (success), * CHECKSUM_UNNECESSARY means, that no more checks are required. * Otherwise, csum completion requires chacksumming packet body, * including udp header and folding it to skb->csum. */static int udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,			     unsigned short ulen, u32 saddr, u32 daddr){	if (uh->check == 0) {		skb->ip_summed = CHECKSUM_UNNECESSARY;	} else if (skb->ip_summed == CHECKSUM_HW) {		skb->ip_summed = CHECKSUM_UNNECESSARY;		if (!udp_check(uh, ulen, saddr, daddr, skb->csum))			return 0;		NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "udp v4 hw csum failure.\n"));		skb->ip_summed = CHECKSUM_NONE;	}	if (skb->ip_summed != CHECKSUM_UNNECESSARY)		skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);	/* Probably, we should checksum udp header (it should be in cache	 * in any case) and data in tiny packets (< rx copybreak).	 */	return 0;}/* *	All we need to do is get the socket, and then do a checksum.  */ int udp_rcv(struct sk_buff *skb){  	struct sock *sk;  	struct udphdr *uh;	unsigned short ulen;	struct rtable *rt = (struct rtable*)skb->dst;	u32 saddr = skb->nh.iph->saddr;	u32 daddr = skb->nh.iph->daddr;	int len = skb->len;  	IP_INC_STATS_BH(IpInDelivers);	/*	 *	Validate the packet and the UDP length.	 */	if (!pskb_may_pull(skb, sizeof(struct udphdr)))		goto no_header;	ulen = ntohs(skb->h.uh->len);	if (ulen > len || ulen < sizeof(*uh))		goto short_packet;	if (pskb_trim(skb, ulen))		goto short_packet;  	uh = skb->h.uh;	if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0)		goto csum_error;	if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))		return udp_v4_mcast_deliver(skb, uh, saddr, daddr);	sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex);	if (sk != NULL) {		udp_queue_rcv_skb(sk, skb);		sock_put(sk);		return 0;	}	/* No socket. Drop packet silently, if checksum is wrong */	if (udp_checksum_complete(skb))		goto csum_error;	UDP_INC_STATS_BH(UdpNoPorts);	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);	/*	 * Hmm.  We got an UDP packet to a port to which we	 * don't wanna listen.  Ignore it.	 */	kfree_skb(skb);	return(0);short_packet:	NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));no_header:	UDP_INC_STATS_BH(UdpInErrors);	kfree_skb(skb);	return(0);csum_error:	/* 	 * RFC1122: OK.  Discards the bad packet silently (as far as 	 * the network is concerned, anyway) as per 4.1.3.4 (MUST). 	 */	NETDEBUG(if (net_ratelimit())		 printk(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",			NIPQUAD(saddr),			ntohs(uh->source),			NIPQUAD(daddr),			ntohs(uh->dest),			ulen));	UDP_INC_STATS_BH(UdpInErrors);	kfree_skb(skb);	return(0);}static void get_udp_sock(struct sock *sp, char *tmpbuf, int i){	unsigned int dest, src;	__u16 destp, srcp;	dest  = sp->daddr;	src   = sp->rcv_saddr;	destp = ntohs(sp->dport);	srcp  = ntohs(sp->sport);	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p",		i, src, srcp, dest, destp, sp->state, 		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),		0, 0L, 0,		sock_i_uid(sp), 0,		sock_i_ino(sp),		atomic_read(&sp->refcnt), sp);}int udp_get_info(char *buffer, char **start, off_t offset, int length){	int len = 0, num = 0, i;	off_t pos = 0;	off_t begin;	char tmpbuf[129];	if (offset < 128) 		len += sprintf(buffer, "%-127s\n",			       "  sl  local_address rem_address   st tx_queue "			       "rx_queue tr tm->when retrnsmt   uid  timeout inode");	pos = 128;	read_lock(&udp_hash_lock);	for (i = 0; i < UDP_HTABLE_SIZE; i++) {		struct sock *sk;		for (sk = udp_hash[i]; sk; sk = sk->next, num++) {			if (sk->family != PF_INET)				continue;			pos += 128;			if (pos <= offset)				continue;			get_udp_sock(sk, tmpbuf, i);			len += sprintf(buffer+len, "%-127s\n", tmpbuf);			if(len >= length)				goto out;		}	}out:	read_unlock(&udp_hash_lock);	begin = len - (pos - offset);	*start = buffer + begin;	len -= begin;	if(len > length)		len = length;	if (len < 0)		len = 0; 	return len;}struct proto udp_prot = { 	name:		"UDP",	close:		udp_close,	connect:	udp_connect,	disconnect:	udp_disconnect,	ioctl:		udp_ioctl,	setsockopt:	ip_setsockopt,	getsockopt:	ip_getsockopt,	sendmsg:	udp_sendmsg,	recvmsg:	udp_recvmsg,	backlog_rcv:	udp_queue_rcv_skb,	hash:		udp_v4_hash,	unhash:		udp_v4_unhash,	get_port:	udp_v4_get_port,};

⌨️ 快捷键说明

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