/*
   Assumptions:
   - if device has no dev->hard_header routine, it adds and removes ll header
     inside itself. In this case ll header is invisible outside of device,
     but higher levels still should reserve dev->hard_header_len.
     Some devices are enough clever to reallocate skb, when header
     will not fit to reserved space (tunnel), another ones are silly
     (PPP).
   - packet socket receives packets with pulled ll header,
     so that SOCK_RAW should push it back.

On receive:
-----------

Incoming, dev->hard_header!=NULL
   mac_header -> ll header
   data       -> data

Outgoing, dev->hard_header!=NULL
   mac_header -> ll header
   data       -> ll header

Incoming, dev->hard_header==NULL
   mac_header -> UNKNOWN position. It is very likely, that it points to ll
         header.  PPP makes it, that is wrong, because introduce
         assymetry between rx and tx paths.
   data       -> data

Outgoing, dev->hard_header==NULL
   mac_header -> data. ll header is still not built!
   data       -> data

Resume
  If dev->hard_header==NULL we are unlikely to restore sensible ll header.


On transmit:
------------

dev->hard_header != NULL
   mac_header -> ll header
   data       -> ll header

dev->hard_header == NULL (ll header is added by device, we cannot control it)
   mac_header -> data
   data       -> data

   We should set nh.raw on output to correct posistion,
   packet classifier depends on it.
 */

/* Private packet socket structures. */

struct packet_mclist
{
    struct packet_mclist    *next;
    int            ifindex;
    int            count;
    unsigned short        type;
    unsigned short        alen;
    unsigned char        addr[MAX_ADDR_LEN];
};
/* identical to struct packet_mreq except it has
 * a longer address field.
 */
struct packet_mreq_max
{
    int        mr_ifindex;
    unsigned short    mr_type;
    unsigned short    mr_alen;
    unsigned char    mr_address[MAX_ADDR_LEN];
};

#ifdef CONFIG_PACKET_MMAP
static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing);
#endif

static void packet_flush_mclist(struct sock *sk);

struct packet_sock {
    /* struct sock has to be the first member of packet_sock */
    struct sock        sk;
    struct tpacket_stats    stats;
#ifdef CONFIG_PACKET_MMAP
    char *            *pg_vec;
    unsigned int        head;
    unsigned int            frames_per_block;
    unsigned int        frame_size;
    unsigned int        frame_max;
    int            copy_thresh;
#endif
    struct packet_type    prot_hook;
    spinlock_t        bind_lock;
    struct mutex        pg_vec_lock;
    unsigned int        running:1,    /* prot_hook is attached*/
                auxdata:1,
                origdev:1;
    int            ifindex;    /* bound device        */
    __be16            num;
    struct packet_mclist    *mclist;
#ifdef CONFIG_PACKET_MMAP
    atomic_t        mapped;
    unsigned int            pg_vec_order;
    unsigned int        pg_vec_pages;
    unsigned int        pg_vec_len;
    enum tpacket_versions    tp_version;
    unsigned int        tp_hdrlen;
    unsigned int        tp_reserve;
#endif
};

/*
 *    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 (!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);
    mutex_init(&po->pg_vec_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(&net->packet.sklist_lock);
    sk_add_node(sk, &net->packet.sklist);
    sock_prot_inuse_add(net, &packet_proto, 1);
    write_unlock_bh(&net->packet.sklist_lock);
    return(0);
out:
    return err;
}

Reply via email to