packet: handle too big packets for PACKET_V3
[pandora-kernel.git] / net / packet / af_packet.c
index b85c67c..93896d2 100644 (file)
@@ -441,14 +441,10 @@ static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts,
 {
        struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
 
-       if (shhwtstamps) {
-               if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) &&
-                   ktime_to_timespec_cond(shhwtstamps->syststamp, ts))
-                       return TP_STATUS_TS_SYS_HARDWARE;
-               if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
-                   ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts))
-                       return TP_STATUS_TS_RAW_HARDWARE;
-       }
+       if (shhwtstamps &&
+           (flags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
+           ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts))
+               return TP_STATUS_TS_RAW_HARDWARE;
 
        if (ktime_to_timespec_cond(skb->tstamp, ts))
                return TP_STATUS_TS_SOFTWARE;
@@ -636,6 +632,7 @@ static void init_prb_bdqc(struct packet_sock *po,
        p1->tov_in_jiffies = msecs_to_jiffies(p1->retire_blk_tov);
        p1->blk_sizeof_priv = req_u->req3.tp_sizeof_priv;
 
+       p1->max_frame_len = p1->kblk_size - BLK_PLUS_PRIV(p1->blk_sizeof_priv);
        prb_init_ft_ops(p1, req_u);
        prb_setup_retire_blk_timer(po, tx_ring);
        prb_open_block(p1, pbd);
@@ -1946,6 +1943,18 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                        if ((int)snaplen < 0)
                                snaplen = 0;
                }
+       } else if (unlikely(macoff + snaplen >
+                           GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len)) {
+               u32 nval;
+
+               nval = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len - macoff;
+               pr_err_once("tpacket_rcv: packet too big, clamped from %u to %u. macoff=%u\n",
+                           snaplen, nval, macoff);
+               snaplen = nval;
+               if (unlikely((int)snaplen < 0)) {
+                       snaplen = 0;
+                       macoff = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len;
+               }
        }
        spin_lock(&sk->sk_receive_queue.lock);
        h.raw = packet_current_rx_frame(po, skb,
@@ -3071,10 +3080,8 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
                break;
        case PACKET_MR_PROMISC:
                return dev_set_promiscuity(dev, what);
-               break;
        case PACKET_MR_ALLMULTI:
                return dev_set_allmulti(dev, what);
-               break;
        case PACKET_MR_UNICAST:
                if (i->alen != dev->addr_len)
                        return -EINVAL;
@@ -3789,6 +3796,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                        goto out;
                if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
                        goto out;
+               if (po->tp_version >= TPACKET_V3 &&
+                   (int)(req->tp_block_size -
+                         BLK_PLUS_PRIV(req_u->req3.tp_sizeof_priv)) <= 0)
+                       goto out;
                if (unlikely(req->tp_frame_size < po->tp_hdrlen +
                                        po->tp_reserve))
                        goto out;