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

📄 af_packet.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	sll->sll_pkttype = skb->pkt_type;	if (unlikely(po->origdev))		sll->sll_ifindex = orig_dev->ifindex;	else		sll->sll_ifindex = dev->ifindex;	h->tp_status = status;	smp_mb();	{		struct page *p_start, *p_end;		u8 *h_end = (u8 *)h + macoff + snaplen - 1;		p_start = virt_to_page(h);		p_end = virt_to_page(h_end);		while (p_start <= p_end) {			flush_dcache_page(p_start);			p_start++;		}	}	sk->sk_data_ready(sk, 0);drop_n_restore:	if (skb_head != skb->data && skb_shared(skb)) {		skb->data = skb_head;		skb->len = skb_len;	}drop:	kfree_skb(skb);	return 0;ring_is_full:	po->stats.tp_drops++;	spin_unlock(&sk->sk_receive_queue.lock);	sk->sk_data_ready(sk, 0);	if (copy_skb)		kfree_skb(copy_skb);	goto drop_n_restore;}#endifstatic int packet_sendmsg(struct kiocb *iocb, struct socket *sock,			  struct msghdr *msg, size_t len){	struct sock *sk = sock->sk;	struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;	struct sk_buff *skb;	struct net_device *dev;	__be16 proto;	unsigned char *addr;	int ifindex, err, reserve = 0;	/*	 *	Get and verify the address.	 */	if (saddr == NULL) {		struct packet_sock *po = pkt_sk(sk);		ifindex	= po->ifindex;		proto	= po->num;		addr	= NULL;	} else {		err = -EINVAL;		if (msg->msg_namelen < sizeof(struct sockaddr_ll))			goto out;		if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr)))			goto out;		ifindex	= saddr->sll_ifindex;		proto	= saddr->sll_protocol;		addr	= saddr->sll_addr;	}	dev = dev_get_by_index(&init_net, ifindex);	err = -ENXIO;	if (dev == NULL)		goto out_unlock;	if (sock->type == SOCK_RAW)		reserve = dev->hard_header_len;	err = -ENETDOWN;	if (!(dev->flags & IFF_UP))		goto out_unlock;	err = -EMSGSIZE;	if (len > dev->mtu+reserve)		goto out_unlock;	skb = sock_alloc_send_skb(sk, len + LL_RESERVED_SPACE(dev),				msg->msg_flags & MSG_DONTWAIT, &err);	if (skb==NULL)		goto out_unlock;	skb_reserve(skb, LL_RESERVED_SPACE(dev));	skb_reset_network_header(skb);	err = -EINVAL;	if (sock->type == SOCK_DGRAM &&	    dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len) < 0)		goto out_free;	/* Returns -EFAULT on error */	err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);	if (err)		goto out_free;	skb->protocol = proto;	skb->dev = dev;	skb->priority = sk->sk_priority;	/*	 *	Now send it	 */	err = dev_queue_xmit(skb);	if (err > 0 && (err = net_xmit_errno(err)) != 0)		goto out_unlock;	dev_put(dev);	return(len);out_free:	kfree_skb(skb);out_unlock:	if (dev)		dev_put(dev);out:	return err;}/* *	Close a PACKET socket. This is fairly simple. We immediately go *	to 'closed' state and remove our protocol entry in the device list. */static int packet_release(struct socket *sock){	struct sock *sk = sock->sk;	struct packet_sock *po;	if (!sk)		return 0;	po = pkt_sk(sk);	write_lock_bh(&packet_sklist_lock);	sk_del_node_init(sk);	write_unlock_bh(&packet_sklist_lock);	/*	 *	Unhook packet receive handler.	 */	if (po->running) {		/*		 *	Remove the protocol hook		 */		dev_remove_pack(&po->prot_hook);		po->running = 0;		po->num = 0;		__sock_put(sk);	}	packet_flush_mclist(sk);#ifdef CONFIG_PACKET_MMAP	if (po->pg_vec) {		struct tpacket_req req;		memset(&req, 0, sizeof(req));		packet_set_ring(sk, &req, 1);	}#endif	/*	 *	Now the socket is dead. No more input will appear.	 */	sock_orphan(sk);	sock->sk = NULL;	/* Purge queues */	skb_queue_purge(&sk->sk_receive_queue);	sk_refcnt_debug_release(sk);	sock_put(sk);	return 0;}/* *	Attach a packet hook. */static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protocol){	struct packet_sock *po = pkt_sk(sk);	/*	 *	Detach an existing hook if present.	 */	lock_sock(sk);	spin_lock(&po->bind_lock);	if (po->running) {		__sock_put(sk);		po->running = 0;		po->num = 0;		spin_unlock(&po->bind_lock);		dev_remove_pack(&po->prot_hook);		spin_lock(&po->bind_lock);	}	po->num = protocol;	po->prot_hook.type = protocol;	po->prot_hook.dev = dev;	po->ifindex = dev ? dev->ifindex : 0;	if (protocol == 0)		goto out_unlock;	if (!dev || (dev->flags & IFF_UP)) {		dev_add_pack(&po->prot_hook);		sock_hold(sk);		po->running = 1;	} else {		sk->sk_err = ENETDOWN;		if (!sock_flag(sk, SOCK_DEAD))			sk->sk_error_report(sk);	}out_unlock:	spin_unlock(&po->bind_lock);	release_sock(sk);	return 0;}/* *	Bind a packet socket to a device */static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int addr_len){	struct sock *sk=sock->sk;	char name[15];	struct net_device *dev;	int err = -ENODEV;	/*	 *	Check legality	 */	if (addr_len != sizeof(struct sockaddr))		return -EINVAL;	strlcpy(name,uaddr->sa_data,sizeof(name));	dev = dev_get_by_name(&init_net, name);	if (dev) {		err = packet_do_bind(sk, dev, pkt_sk(sk)->num);		dev_put(dev);	}	return err;}static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){	struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr;	struct sock *sk=sock->sk;	struct net_device *dev = NULL;	int err;	/*	 *	Check legality	 */	if (addr_len < sizeof(struct sockaddr_ll))		return -EINVAL;	if (sll->sll_family != AF_PACKET)		return -EINVAL;	if (sll->sll_ifindex) {		err = -ENODEV;		dev = dev_get_by_index(&init_net, sll->sll_ifindex);		if (dev == NULL)			goto out;	}	err = packet_do_bind(sk, dev, sll->sll_protocol ? : pkt_sk(sk)->num);	if (dev)		dev_put(dev);out:	return err;}static struct proto packet_proto = {	.name	  = "PACKET",	.owner	  = THIS_MODULE,	.obj_size = sizeof(struct packet_sock),};/* *	Create a packet of type SOCK_PACKET. */static int packet_create(struct net *net, struct socket *sock, int protocol){	struct sock *sk;	struct packet_sock *po;	__be16 proto = (__force __be16)protocol; /* weird, but documented */	int err;	if (net != &init_net)		return -EAFNOSUPPORT;	if (!capable(CAP_NET_RAW))		return -EPERM;	if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW &&	    sock->type != SOCK_PACKET)		return -ESOCKTNOSUPPORT;	sock->state = SS_UNCONNECTED;	err = -ENOBUFS;	sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto);	if (sk == NULL)		goto out;	sock->ops = &packet_ops;	if (sock->type == SOCK_PACKET)		sock->ops = &packet_ops_spkt;	sock_init_data(sock, sk);	po = pkt_sk(sk);	sk->sk_family = PF_PACKET;	po->num = proto;	sk->sk_destruct = packet_sock_destruct;	sk_refcnt_debug_inc(sk);	/*	 *	Attach a protocol block	 */	spin_lock_init(&po->bind_lock);	po->prot_hook.func = packet_rcv;	if (sock->type == SOCK_PACKET)		po->prot_hook.func = packet_rcv_spkt;	po->prot_hook.af_packet_priv = sk;	if (proto) {		po->prot_hook.type = proto;		dev_add_pack(&po->prot_hook);		sock_hold(sk);		po->running = 1;	}	write_lock_bh(&packet_sklist_lock);	sk_add_node(sk, &packet_sklist);	write_unlock_bh(&packet_sklist_lock);	return(0);out:	return err;}/* *	Pull a packet from our receive queue and hand it to the user. *	If necessary we block. */static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,			  struct msghdr *msg, size_t len, int flags){	struct sock *sk = sock->sk;	struct sk_buff *skb;	int copied, err;	struct sockaddr_ll *sll;	err = -EINVAL;	if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))		goto out;#if 0	/* What error should we return now? EUNATTACH? */	if (pkt_sk(sk)->ifindex < 0)		return -ENODEV;#endif	/*	 *	Call the generic datagram receiver. This handles all sorts	 *	of horrible races and re-entrancy so we can forget about it	 *	in the protocol layers.	 *	 *	Now it will return ENETDOWN, if device have just gone down,	 *	but then it will block.	 */	skb=skb_recv_datagram(sk,flags,flags&MSG_DONTWAIT,&err);	/*	 *	An error occurred so return it. Because skb_recv_datagram()	 *	handles the blocking we don't see and worry about blocking	 *	retries.	 */	if (skb == NULL)		goto out;	/*	 *	If the address length field is there to be filled in, we fill	 *	it in now.	 */	sll = &PACKET_SKB_CB(skb)->sa.ll;	if (sock->type == SOCK_PACKET)		msg->msg_namelen = sizeof(struct sockaddr_pkt);	else		msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr);	/*	 *	You lose any data beyond the buffer you gave. If it worries a	 *	user program they can ask the device for its MTU anyway.	 */	copied = skb->len;	if (copied > len)	{		copied=len;		msg->msg_flags|=MSG_TRUNC;	}	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);	if (err)		goto out_free;	sock_recv_timestamp(msg, sk, skb);	if (msg->msg_name)		memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,		       msg->msg_namelen);	if (pkt_sk(sk)->auxdata) {		struct tpacket_auxdata aux;		aux.tp_status = TP_STATUS_USER;		if (skb->ip_summed == CHECKSUM_PARTIAL)			aux.tp_status |= TP_STATUS_CSUMNOTREADY;		aux.tp_len = PACKET_SKB_CB(skb)->origlen;		aux.tp_snaplen = skb->len;		aux.tp_mac = 0;		aux.tp_net = skb_network_offset(skb);		put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);	}	/*	 *	Free or return the buffer as appropriate. Again this	 *	hides all the races and re-entrancy issues from us.	 */	err = (flags&MSG_TRUNC) ? skb->len : copied;out_free:	skb_free_datagram(sk, skb);out:	return err;}static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr,			       int *uaddr_len, int peer){	struct net_device *dev;	struct sock *sk	= sock->sk;	if (peer)		return -EOPNOTSUPP;	uaddr->sa_family = AF_PACKET;	dev = dev_get_by_index(&init_net, pkt_sk(sk)->ifindex);	if (dev) {		strlcpy(uaddr->sa_data, dev->name, 15);		dev_put(dev);	} else		memset(uaddr->sa_data, 0, 14);	*uaddr_len = sizeof(*uaddr);	return 0;}static int packet_getname(struct socket *sock, struct sockaddr *uaddr,			  int *uaddr_len, int peer){	struct net_device *dev;	struct sock *sk = sock->sk;	struct packet_sock *po = pkt_sk(sk);	struct sockaddr_ll *sll = (struct sockaddr_ll*)uaddr;	if (peer)		return -EOPNOTSUPP;	sll->sll_family = AF_PACKET;	sll->sll_ifindex = po->ifindex;	sll->sll_protocol = po->num;	dev = dev_get_by_index(&init_net, po->ifindex);	if (dev) {		sll->sll_hatype = dev->type;		sll->sll_halen = dev->addr_len;		memcpy(sll->sll_addr, dev->dev_addr, dev->addr_len);		dev_put(dev);	} else {		sll->sll_hatype = 0;	/* Bad: we have no ARPHRD_UNSPEC */		sll->sll_halen = 0;	}	*uaddr_len = offsetof(struct sockaddr_ll, sll_addr) + sll->sll_halen;	return 0;}static void packet_dev_mc(struct net_device *dev, struct packet_mclist *i, int what){	switch (i->type) {	case PACKET_MR_MULTICAST:		if (what > 0)			dev_mc_add(dev, i->addr, i->alen, 0);		else			dev_mc_delete(dev, i->addr, i->alen, 0);		break;	case PACKET_MR_PROMISC:		dev_set_promiscuity(dev, what);		break;	case PACKET_MR_ALLMULTI:		dev_set_allmulti(dev, what);		break;	default:;	}}static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what){	for ( ; i; i=i->next) {		if (i->ifindex == dev->ifindex)			packet_dev_mc(dev, i, what);	}}static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq){	struct packet_sock *po = pkt_sk(sk);	struct packet_mclist *ml, *i;	struct net_device *dev;	int err;	rtnl_lock();	err = -ENODEV;	dev = __dev_get_by_index(&init_net, mreq->mr_ifindex);	if (!dev)		goto done;	err = -EINVAL;	if (mreq->mr_alen > dev->addr_len)		goto done;	err = -ENOBUFS;	i = kmalloc(sizeof(*i), GFP_KERNEL);	if (i == NULL)		goto done;	err = 0;	for (ml = po->mclist; ml; ml = ml->next) {		if (ml->ifindex == mreq->mr_ifindex &&		    ml->type == mreq->mr_type &&		    ml->alen == mreq->mr_alen &&		    memcmp(ml->addr, mreq->mr_address, ml->alen) == 0) {			ml->count++;			/* Free the new element ... */			kfree(i);			goto done;		}	}	i->type = mreq->mr_type;	i->ifindex = mreq->mr_ifindex;	i->alen = mreq->mr_alen;	memcpy(i->addr, mreq->mr_address, i->alen);	i->count = 1;	i->next = po->mclist;	po->mclist = i;	packet_dev_mc(dev, i, +1);done:	rtnl_unlock();	return err;}static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq){	struct packet_mclist *ml, **mlp;	rtnl_lock();	for (mlp = &pkt_sk(sk)->mclist; (ml = *mlp) != NULL; mlp = &ml->next) {		if (ml->ifindex == mreq->mr_ifindex &&		    ml->type == mreq->mr_type &&		    ml->alen == mreq->mr_alen &&		    memcmp(ml->addr, mreq->mr_address, ml->alen) == 0) {			if (--ml->count == 0) {				struct net_device *dev;				*mlp = ml->next;				dev = dev_get_by_index(&init_net, ml->ifindex);				if (dev) {					packet_dev_mc(dev, ml, -1);					dev_put(dev);				}				kfree(ml);			}			rtnl_unlock();			return 0;		}	}	rtnl_unlock();	return -EADDRNOTAVAIL;}static void packet_flush_mclist(struct sock *sk){	struct packet_sock *po = pkt_sk(sk);	struct packet_mclist *ml;	if (!po->mclist)		return;	rtnl_lock();	while ((ml = po->mclist) != NULL) {		struct net_device *dev;		po->mclist = ml->next;		if ((dev = dev_get_by_index(&init_net, ml->ifindex)) != NULL) {			packet_dev_mc(dev, ml, -1);			dev_put(dev);		}		kfree(ml);	}	rtnl_unlock();}static intpacket_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)

⌨️ 快捷键说明

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