static int packet_release(struct socket *sock) { struct sock *sk = sock->sk; struct sock **skp; if (!sk) return 0; write_lock_bh(&packet_sklist_lock); for (skp = &packet_sklist; *skp; skp = &(*skp)->next) { if (*skp == sk) { *skp = sk->next; __sock_put(sk); break; } } write_unlock_bh(&packet_sklist_lock); /* * Unhook packet receive handler. */ if (sk->protinfo.af_packet->running) { /* * Remove the protocol hook */ dev_remove_pack(&sk->protinfo.af_packet->prot_hook); sk->protinfo.af_packet->running = 0; __sock_put(sk); } #ifdef CONFIG_PACKET_MULTICAST packet_flush_mclist(sk); #endif #ifdef CONFIG_PACKET_MMAP if (sk->protinfo.af_packet->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->receive_queue); sock_put(sk); return 0; }
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); } #ifdef CONFIG_PACKET_MULTICAST packet_flush_mclist(sk); #endif #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); sock_put(sk); return 0; }
static int packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { struct sock *sk = sock->sk; int ret; if (level != SOL_PACKET) return -ENOPROTOOPT; switch(optname) { #ifdef CONFIG_PACKET_MULTICAST case PACKET_ADD_MEMBERSHIP: case PACKET_DROP_MEMBERSHIP: { struct packet_mreq mreq; if (optlen<sizeof(mreq)) return -EINVAL; if (copy_from_user(&mreq,optval,sizeof(mreq))) return -EFAULT; if (optname == PACKET_ADD_MEMBERSHIP) ret = packet_mc_add(sk, &mreq); else ret = packet_mc_drop(sk, &mreq); return ret; } #endif #ifdef CONFIG_PACKET_MMAP case PACKET_RX_RING: { struct tpacket_req req; if (optlen<sizeof(req)) return -EINVAL; if (copy_from_user(&req,optval,sizeof(req))) return -EFAULT; return packet_set_ring(sk, &req, 0); } case PACKET_COPY_THRESH: { int val; if (optlen!=sizeof(val)) return -EINVAL; if (copy_from_user(&val,optval,sizeof(val))) return -EFAULT; pkt_sk(sk)->copy_thresh = val; return 0; } #endif default: return -ENOPROTOOPT; } }