📄 af_packet.c
字号:
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 + -