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

📄 raw.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			if (!daddr)				goto done;			daddr = ipc.opt->faddr;		}	}	tos = RT_CONN_FLAGS(sk);	if (msg->msg_flags & MSG_DONTROUTE)		tos |= RTO_ONLINK;	if (MULTICAST(daddr)) {		if (!ipc.oif)			ipc.oif = inet->mc_index;		if (!saddr)			saddr = inet->mc_addr;	}	{		struct flowi fl = { .oif = ipc.oif,				    .nl_u = { .ip4_u =					      { .daddr = daddr,						.saddr = saddr,						.tos = tos } },				    .proto = inet->hdrincl ? IPPROTO_RAW :							     sk->sk_protocol,				  };		if (!inet->hdrincl) {			err = raw_probe_proto_opt(&fl, msg);			if (err)				goto done;		}		security_sk_classify_flow(sk, &fl);		err = ip_route_output_flow(&rt, &fl, sk, 1);	}	if (err)		goto done;	err = -EACCES;	if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST))		goto done;	if (msg->msg_flags & MSG_CONFIRM)		goto do_confirm;back_from_confirm:	if (inet->hdrincl)		err = raw_send_hdrinc(sk, msg->msg_iov, len,					rt, msg->msg_flags);	 else {		if (!ipc.addr)			ipc.addr = rt->rt_dst;		lock_sock(sk);		err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0,					&ipc, rt, msg->msg_flags);		if (err)			ip_flush_pending_frames(sk);		else if (!(msg->msg_flags & MSG_MORE))			err = ip_push_pending_frames(sk);		release_sock(sk);	}done:	if (free)		kfree(ipc.opt);	ip_rt_put(rt);out:	if (err < 0)		return err;	return len;do_confirm:	dst_confirm(&rt->u.dst);	if (!(msg->msg_flags & MSG_PROBE) || len)		goto back_from_confirm;	err = 0;	goto done;}static void raw_close(struct sock *sk, long timeout){	/*	 * Raw sockets may have direct kernel refereneces. Kill them.	 */	ip_ra_control(sk, 0, NULL);	sk_common_release(sk);}/* This gets rid of all the nasties in af_inet. -DaveM */static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len){	struct inet_sock *inet = inet_sk(sk);	struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;	int ret = -EINVAL;	int chk_addr_ret;	if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in))		goto out;	chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);	ret = -EADDRNOTAVAIL;	if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL &&	    chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)		goto out;	inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr;	if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)		inet->saddr = 0;  /* Use device */	sk_dst_reset(sk);	ret = 0;out:	return ret;}/* *	This should be easy, if there is something there *	we return it, otherwise we block. */static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,		       size_t len, int noblock, int flags, int *addr_len){	struct inet_sock *inet = inet_sk(sk);	size_t copied = 0;	int err = -EOPNOTSUPP;	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;	struct sk_buff *skb;	if (flags & MSG_OOB)		goto out;	if (addr_len)		*addr_len = sizeof(*sin);	if (flags & MSG_ERRQUEUE) {		err = ip_recv_error(sk, msg, len);		goto out;	}	skb = skb_recv_datagram(sk, flags, noblock, &err);	if (!skb)		goto out;	copied = skb->len;	if (len < copied) {		msg->msg_flags |= MSG_TRUNC;		copied = len;	}	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);	if (err)		goto done;	sock_recv_timestamp(msg, sk, skb);	/* Copy the address. */	if (sin) {		sin->sin_family = AF_INET;		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;		sin->sin_port = 0;		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));	}	if (inet->cmsg_flags)		ip_cmsg_recv(msg, skb);	if (flags & MSG_TRUNC)		copied = skb->len;done:	skb_free_datagram(sk, skb);out:	if (err)		return err;	return copied;}static int raw_init(struct sock *sk){	struct raw_sock *rp = raw_sk(sk);	if (inet_sk(sk)->num == IPPROTO_ICMP)		memset(&rp->filter, 0, sizeof(rp->filter));	return 0;}static int raw_seticmpfilter(struct sock *sk, char __user *optval, int optlen){	if (optlen > sizeof(struct icmp_filter))		optlen = sizeof(struct icmp_filter);	if (copy_from_user(&raw_sk(sk)->filter, optval, optlen))		return -EFAULT;	return 0;}static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *optlen){	int len, ret = -EFAULT;	if (get_user(len, optlen))		goto out;	ret = -EINVAL;	if (len < 0)		goto out;	if (len > sizeof(struct icmp_filter))		len = sizeof(struct icmp_filter);	ret = -EFAULT;	if (put_user(len, optlen) ||	    copy_to_user(optval, &raw_sk(sk)->filter, len))		goto out;	ret = 0;out:	return ret;}static int do_raw_setsockopt(struct sock *sk, int level, int optname,			  char __user *optval, int optlen){	if (optname == ICMP_FILTER) {		if (inet_sk(sk)->num != IPPROTO_ICMP)			return -EOPNOTSUPP;		else			return raw_seticmpfilter(sk, optval, optlen);	}	return -ENOPROTOOPT;}static int raw_setsockopt(struct sock *sk, int level, int optname,			  char __user *optval, int optlen){	if (level != SOL_RAW)		return ip_setsockopt(sk, level, optname, optval, optlen);	return do_raw_setsockopt(sk, level, optname, optval, optlen);}#ifdef CONFIG_COMPATstatic int compat_raw_setsockopt(struct sock *sk, int level, int optname,				 char __user *optval, int optlen){	if (level != SOL_RAW)		return compat_ip_setsockopt(sk, level, optname, optval, optlen);	return do_raw_setsockopt(sk, level, optname, optval, optlen);}#endifstatic int do_raw_getsockopt(struct sock *sk, int level, int optname,			  char __user *optval, int __user *optlen){	if (optname == ICMP_FILTER) {		if (inet_sk(sk)->num != IPPROTO_ICMP)			return -EOPNOTSUPP;		else			return raw_geticmpfilter(sk, optval, optlen);	}	return -ENOPROTOOPT;}static int raw_getsockopt(struct sock *sk, int level, int optname,			  char __user *optval, int __user *optlen){	if (level != SOL_RAW)		return ip_getsockopt(sk, level, optname, optval, optlen);	return do_raw_getsockopt(sk, level, optname, optval, optlen);}#ifdef CONFIG_COMPATstatic int compat_raw_getsockopt(struct sock *sk, int level, int optname,				 char __user *optval, int __user *optlen){	if (level != SOL_RAW)		return compat_ip_getsockopt(sk, level, optname, optval, optlen);	return do_raw_getsockopt(sk, level, optname, optval, optlen);}#endifstatic int raw_ioctl(struct sock *sk, int cmd, unsigned long arg){	switch (cmd) {		case SIOCOUTQ: {			int amount = atomic_read(&sk->sk_wmem_alloc);			return put_user(amount, (int __user *)arg);		}		case SIOCINQ: {			struct sk_buff *skb;			int amount = 0;			spin_lock_bh(&sk->sk_receive_queue.lock);			skb = skb_peek(&sk->sk_receive_queue);			if (skb != NULL)				amount = skb->len;			spin_unlock_bh(&sk->sk_receive_queue.lock);			return put_user(amount, (int __user *)arg);		}		default:#ifdef CONFIG_IP_MROUTE			return ipmr_ioctl(sk, cmd, (void __user *)arg);#else			return -ENOIOCTLCMD;#endif	}}DEFINE_PROTO_INUSE(raw)struct proto raw_prot = {	.name		   = "RAW",	.owner		   = THIS_MODULE,	.close		   = raw_close,	.connect	   = ip4_datagram_connect,	.disconnect	   = udp_disconnect,	.ioctl		   = raw_ioctl,	.init		   = raw_init,	.setsockopt	   = raw_setsockopt,	.getsockopt	   = raw_getsockopt,	.sendmsg	   = raw_sendmsg,	.recvmsg	   = raw_recvmsg,	.bind		   = raw_bind,	.backlog_rcv	   = raw_rcv_skb,	.hash		   = raw_v4_hash,	.unhash		   = raw_v4_unhash,	.obj_size	   = sizeof(struct raw_sock),#ifdef CONFIG_COMPAT	.compat_setsockopt = compat_raw_setsockopt,	.compat_getsockopt = compat_raw_getsockopt,#endif	REF_PROTO_INUSE(raw)};#ifdef CONFIG_PROC_FSstruct raw_iter_state {	int bucket;};#define raw_seq_private(seq) ((struct raw_iter_state *)(seq)->private)static struct sock *raw_get_first(struct seq_file *seq){	struct sock *sk;	struct raw_iter_state* state = raw_seq_private(seq);	for (state->bucket = 0; state->bucket < RAWV4_HTABLE_SIZE; ++state->bucket) {		struct hlist_node *node;		sk_for_each(sk, node, &raw_v4_htable[state->bucket])			if (sk->sk_family == PF_INET)				goto found;	}	sk = NULL;found:	return sk;}static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk){	struct raw_iter_state* state = raw_seq_private(seq);	do {		sk = sk_next(sk);try_again:		;	} while (sk && sk->sk_family != PF_INET);	if (!sk && ++state->bucket < RAWV4_HTABLE_SIZE) {		sk = sk_head(&raw_v4_htable[state->bucket]);		goto try_again;	}	return sk;}static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos){	struct sock *sk = raw_get_first(seq);	if (sk)		while (pos && (sk = raw_get_next(seq, sk)) != NULL)			--pos;	return pos ? NULL : sk;}static void *raw_seq_start(struct seq_file *seq, loff_t *pos){	read_lock(&raw_v4_lock);	return *pos ? raw_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;}static void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct sock *sk;	if (v == SEQ_START_TOKEN)		sk = raw_get_first(seq);	else		sk = raw_get_next(seq, v);	++*pos;	return sk;}static void raw_seq_stop(struct seq_file *seq, void *v){	read_unlock(&raw_v4_lock);}static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i){	struct inet_sock *inet = inet_sk(sp);	__be32 dest = inet->daddr,	       src = inet->rcv_saddr;	__u16 destp = 0,	      srcp  = inet->num;	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",		i, src, srcp, dest, destp, sp->sk_state,		atomic_read(&sp->sk_wmem_alloc),		atomic_read(&sp->sk_rmem_alloc),		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),		atomic_read(&sp->sk_refcnt), sp);	return tmpbuf;}static int raw_seq_show(struct seq_file *seq, void *v){	char tmpbuf[129];	if (v == SEQ_START_TOKEN)		seq_printf(seq, "%-127s\n",			       "  sl  local_address rem_address   st tx_queue "			       "rx_queue tr tm->when retrnsmt   uid  timeout "			       "inode");	else {		struct raw_iter_state *state = raw_seq_private(seq);		seq_printf(seq, "%-127s\n",			   get_raw_sock(v, tmpbuf, state->bucket));	}	return 0;}static const struct seq_operations raw_seq_ops = {	.start = raw_seq_start,	.next  = raw_seq_next,	.stop  = raw_seq_stop,	.show  = raw_seq_show,};static int raw_seq_open(struct inode *inode, struct file *file){	return seq_open_private(file, &raw_seq_ops,			sizeof(struct raw_iter_state));}static const struct file_operations raw_seq_fops = {	.owner	 = THIS_MODULE,	.open	 = raw_seq_open,	.read	 = seq_read,	.llseek	 = seq_lseek,	.release = seq_release_private,};int __init raw_proc_init(void){	if (!proc_net_fops_create(&init_net, "raw", S_IRUGO, &raw_seq_fops))		return -ENOMEM;	return 0;}void __init raw_proc_exit(void){	proc_net_remove(&init_net, "raw");}#endif /* CONFIG_PROC_FS */

⌨️ 快捷键说明

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