*
  * We could use other alignment values, but we must maintain the
  * relationship HH alignment <= LL alignment.
+ *
+ * LL_ALLOCATED_SPACE also takes into account the tailroom the device
+ * may need.
  */
 #define LL_RESERVED_SPACE(dev) \
-       (((dev)->hard_header_len&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
+       ((((dev)->hard_header_len+(dev)->needed_headroom)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
 #define LL_RESERVED_SPACE_EXTRA(dev,extra) \
-       ((((dev)->hard_header_len+extra)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
+       ((((dev)->hard_header_len+(dev)->needed_headroom+(extra))&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
+#define LL_ALLOCATED_SPACE(dev) \
+       ((((dev)->hard_header_len+(dev)->needed_headroom+(dev)->needed_tailroom)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
 
 struct header_ops {
        int     (*create) (struct sk_buff *skb, struct net_device *dev,
        unsigned short          type;   /* interface hardware type      */
        unsigned short          hard_header_len;        /* hardware hdr length  */
 
+       /* extra head- and tailroom the hardware may need, but not in all cases
+        * can this be guaranteed, especially tailroom. Some cases also use
+        * LL_MAX_HEADER instead to allocate the skb.
+        */
+       unsigned short          needed_headroom;
+       unsigned short          needed_tailroom;
+
        struct net_device       *master; /* Pointer to master device of a group,
                                          * which this device is member of.
                                          */
 
                return;
 
        size = arp_hdr_len(skb->dev);
-       send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev),
+       send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev),
                            LL_RESERVED_SPACE(np->dev));
 
        if (!send_skb)
 
 
                dev_hold(dev);
 
-               skb = sock_alloc_send_skb(sk, len+LL_RESERVED_SPACE(dev),
+               skb = sock_alloc_send_skb(sk, len+LL_ALLOCATED_SPACE(dev),
                                          msg->msg_flags & MSG_DONTWAIT, &err);
                if (skb==NULL)
                        goto out_unlock;
 
         *      Allocate a buffer
         */
 
-       skb = alloc_skb(arp_hdr_len(dev) + LL_RESERVED_SPACE(dev), GFP_ATOMIC);
+       skb = alloc_skb(arp_hdr_len(dev) + LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
        if (skb == NULL)
                return NULL;
 
 
        struct iphdr *pip;
        struct igmpv3_report *pig;
 
-       skb = alloc_skb(size + LL_RESERVED_SPACE(dev), GFP_ATOMIC);
+       skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
        if (skb == NULL)
                return NULL;
 
                return -1;
        }
 
-       skb=alloc_skb(IGMP_SIZE+LL_RESERVED_SPACE(dev), GFP_ATOMIC);
+       skb=alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
        if (skb == NULL) {
                ip_rt_put(rt);
                return -1;
 
        struct net_device *dev = d->dev;
        struct sk_buff *skb;
        struct bootp_pkt *b;
-       int hh_len = LL_RESERVED_SPACE(dev);
        struct iphdr *h;
 
        /* Allocate packet */
-       skb = alloc_skb(sizeof(struct bootp_pkt) + hh_len + 15, GFP_KERNEL);
+       skb = alloc_skb(sizeof(struct bootp_pkt) + LL_ALLOCATED_SPACE(dev) + 15,
+                       GFP_KERNEL);
        if (!skb)
                return;
-       skb_reserve(skb, hh_len);
+       skb_reserve(skb, LL_RESERVED_SPACE(dev));
        b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt));
        memset(b, 0, sizeof(struct bootp_pkt));
 
 
                        unsigned int flags)
 {
        struct inet_sock *inet = inet_sk(sk);
-       int hh_len;
        struct iphdr *iph;
        struct sk_buff *skb;
        unsigned int iphlen;
        if (flags&MSG_PROBE)
                goto out;
 
-       hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
-
-       skb = sock_alloc_send_skb(sk, length+hh_len+15,
-                                 flags&MSG_DONTWAIT, &err);
+       skb = sock_alloc_send_skb(sk,
+                                 length + LL_ALLOCATED_SPACE(rt->u.dst.dev) + 15,
+                                 flags & MSG_DONTWAIT, &err);
        if (skb == NULL)
                goto error;
-       skb_reserve(skb, hh_len);
+       skb_reserve(skb, LL_RESERVED_SPACE(rt->u.dst.dev));
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
 
                 *      Allocate buffer.
                 */
 
-               if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
+               if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
                        NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
                        IP6_INC_STATS(ip6_dst_idev(skb->dst),
                                      IPSTATS_MIB_FRAGFAILS);
 
                     IPV6_TLV_PADN, 0 };
 
        /* we assume size > sizeof(ra) here */
-       skb = sock_alloc_send_skb(sk, size + LL_RESERVED_SPACE(dev), 1, &err);
+       skb = sock_alloc_send_skb(sk, size + LL_ALLOCATED_SPACE(dev), 1, &err);
 
        if (!skb)
                return NULL;
        payload_len = len + sizeof(ra);
        full_len = sizeof(struct ipv6hdr) + payload_len;
 
-       skb = sock_alloc_send_skb(sk, LL_RESERVED_SPACE(dev) + full_len, 1, &err);
+       skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + full_len, 1, &err);
 
        if (skb == NULL) {
                rcu_read_lock();
 
 
        skb = sock_alloc_send_skb(sk,
                                  (MAX_HEADER + sizeof(struct ipv6hdr) +
-                                  len + LL_RESERVED_SPACE(dev)),
+                                  len + LL_ALLOCATED_SPACE(dev)),
                                  1, &err);
        if (!skb) {
                ND_PRINTK0(KERN_ERR
 
        buff = sock_alloc_send_skb(sk,
                                   (MAX_HEADER + sizeof(struct ipv6hdr) +
-                                   len + LL_RESERVED_SPACE(dev)),
+                                   len + LL_ALLOCATED_SPACE(dev)),
                                   1, &err);
        if (buff == NULL) {
                ND_PRINTK0(KERN_ERR
 
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct ipv6hdr *iph;
        struct sk_buff *skb;
-       unsigned int hh_len;
        int err;
 
        if (length > rt->u.dst.dev->mtu) {
        if (flags&MSG_PROBE)
                goto out;
 
-       hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
-
-       skb = sock_alloc_send_skb(sk, length+hh_len+15,
-                                 flags&MSG_DONTWAIT, &err);
+       skb = sock_alloc_send_skb(sk,
+                                 length + LL_ALLOCATED_SPACE(rt->u.dst.dev) + 15,
+                                 flags & MSG_DONTWAIT, &err);
        if (skb == NULL)
                goto error;
-       skb_reserve(skb, hh_len);
+       skb_reserve(skb, LL_RESERVED_SPACE(rt->u.dst.dev));
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
 
        if (len > dev->mtu+reserve)
                goto out_unlock;
 
-       skb = sock_alloc_send_skb(sk, len + LL_RESERVED_SPACE(dev),
+       skb = sock_alloc_send_skb(sk, len + LL_ALLOCATED_SPACE(dev),
                                msg->msg_flags & MSG_DONTWAIT, &err);
        if (skb==NULL)
                goto out_unlock;
 
        struct dst_entry *dst = skb->dst;
        int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev)
                - skb_headroom(skb);
+       int ntail = dst->dev->needed_tailroom - skb_tailroom(skb);
 
-       if (nhead > 0)
-               return pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
+       if (nhead > 0 || ntail > 0)
+               return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
 
-       /* Check tail too... */
        return 0;
 }