Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Oct 2008 16:37:04 +0000 (09:37 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Oct 2008 16:37:04 +0000 (09:37 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6:
  af_key: Free dumping state on socket close
  XFRM,IPv6: initialize ip6_dst_blackhole_ops.kmem_cachep
  ipv6: NULL pointer dereferrence in tcp_v6_send_ack
  tcp: Fix NULL dereference in tcp_4_send_ack()
  sctp: Fix kernel panic while process protocol violation parameter
  iucv: Fix mismerge again.
  ipsec: Fix pskb_expand_head corruption in xfrm_state_check_space

include/net/sctp/sm.h
net/ipv4/tcp_ipv4.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/iucv/iucv.c
net/key/af_key.c
net/sctp/sm_make_chunk.c
net/sctp/sm_statefuns.c
net/xfrm/xfrm_output.c

index 2481173..029a54a 100644 (file)
@@ -227,6 +227,9 @@ struct sctp_chunk *sctp_make_abort_violation(const struct sctp_association *,
                                   const struct sctp_chunk *,
                                   const __u8 *,
                                   const size_t );
+struct sctp_chunk *sctp_make_violation_paramlen(const struct sctp_association *,
+                                  const struct sctp_chunk *,
+                                  struct sctp_paramhdr *);
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *,
                                  const struct sctp_transport *,
                                  const void *payload,
index 1b4fee2..011478e 100644 (file)
@@ -618,7 +618,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
                        ];
        } rep;
        struct ip_reply_arg arg;
-       struct net *net = dev_net(skb->dev);
+       struct net *net = dev_net(skb->dst->dev);
 
        memset(&rep.th, 0, sizeof(struct tcphdr));
        memset(&arg, 0, sizeof(arg));
index 9af6115..63442a1 100644 (file)
@@ -2688,6 +2688,8 @@ int __init ip6_route_init(void)
        if (ret)
                goto out_kmem_cache;
 
+       ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
+
        /* Registering of the loopback is done before this portion of code,
         * the loopback reference in rt6_info will not be taken, do it
         * manually for init_net */
index b585c85..10e22fd 100644 (file)
@@ -1050,7 +1050,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
        struct tcphdr *th = tcp_hdr(skb), *t1;
        struct sk_buff *buff;
        struct flowi fl;
-       struct net *net = dev_net(skb->dev);
+       struct net *net = dev_net(skb->dst->dev);
        struct sock *ctl_sk = net->ipv6.tcp_sk;
        unsigned int tot_len = sizeof(struct tcphdr);
        __be32 *topt;
index 705959b..d7b54b5 100644 (file)
@@ -524,7 +524,6 @@ static int iucv_enable(void)
        get_online_cpus();
        for_each_online_cpu(cpu)
                smp_call_function_single(cpu, iucv_declare_cpu, NULL, 1);
-       preempt_enable();
        if (cpus_empty(iucv_buffer_cpumask))
                /* No cpu could declare an iucv buffer. */
                goto out_path;
@@ -547,7 +546,9 @@ out:
  */
 static void iucv_disable(void)
 {
+       get_online_cpus();
        on_each_cpu(iucv_retrieve_cpu, NULL, 1);
+       put_online_cpus();
        kfree(iucv_path_table);
 }
 
index d628df9..b7f5a1c 100644 (file)
@@ -73,22 +73,18 @@ static int pfkey_can_dump(struct sock *sk)
        return 0;
 }
 
-static int pfkey_do_dump(struct pfkey_sock *pfk)
+static void pfkey_terminate_dump(struct pfkey_sock *pfk)
 {
-       int rc;
-
-       rc = pfk->dump.dump(pfk);
-       if (rc == -ENOBUFS)
-               return 0;
-
-       pfk->dump.done(pfk);
-       pfk->dump.dump = NULL;
-       pfk->dump.done = NULL;
-       return rc;
+       if (pfk->dump.dump) {
+               pfk->dump.done(pfk);
+               pfk->dump.dump = NULL;
+               pfk->dump.done = NULL;
+       }
 }
 
 static void pfkey_sock_destruct(struct sock *sk)
 {
+       pfkey_terminate_dump(pfkey_sk(sk));
        skb_queue_purge(&sk->sk_receive_queue);
 
        if (!sock_flag(sk, SOCK_DEAD)) {
@@ -310,6 +306,18 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
        return err;
 }
 
+static int pfkey_do_dump(struct pfkey_sock *pfk)
+{
+       int rc;
+
+       rc = pfk->dump.dump(pfk);
+       if (rc == -ENOBUFS)
+               return 0;
+
+       pfkey_terminate_dump(pfk);
+       return rc;
+}
+
 static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *orig)
 {
        *new = *orig;
index b599cbb..d68869f 100644 (file)
@@ -1012,6 +1012,29 @@ end:
        return retval;
 }
 
+struct sctp_chunk *sctp_make_violation_paramlen(
+       const struct sctp_association *asoc,
+       const struct sctp_chunk *chunk,
+       struct sctp_paramhdr *param)
+{
+       struct sctp_chunk *retval;
+       static const char error[] = "The following parameter had invalid length:";
+       size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t) +
+                               sizeof(sctp_paramhdr_t);
+
+       retval = sctp_make_abort(asoc, chunk, payload_len);
+       if (!retval)
+               goto nodata;
+
+       sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION,
+                       sizeof(error) + sizeof(sctp_paramhdr_t));
+       sctp_addto_chunk(retval, sizeof(error), error);
+       sctp_addto_param(retval, sizeof(sctp_paramhdr_t), param);
+
+nodata:
+       return retval;
+}
+
 /* Make a HEARTBEAT chunk.  */
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
                                  const struct sctp_transport *transport,
@@ -1782,11 +1805,6 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
                                        const struct sctp_chunk *chunk,
                                        struct sctp_chunk **errp)
 {
-       static const char error[] = "The following parameter had invalid length:";
-       size_t          payload_len = WORD_ROUND(sizeof(error)) +
-                                               sizeof(sctp_paramhdr_t);
-
-
        /* This is a fatal error.  Any accumulated non-fatal errors are
         * not reported.
         */
@@ -1794,14 +1812,7 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
                sctp_chunk_free(*errp);
 
        /* Create an error chunk and fill it in with our payload. */
-       *errp = sctp_make_op_error_space(asoc, chunk, payload_len);
-
-       if (*errp) {
-               sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION,
-                               sizeof(error) + sizeof(sctp_paramhdr_t));
-               sctp_addto_chunk(*errp, sizeof(error), error);
-               sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param);
-       }
+       *errp = sctp_make_violation_paramlen(asoc, chunk, param);
 
        return 0;
 }
index 8848d32..7c622af 100644 (file)
@@ -119,7 +119,7 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
-                                    void *arg,
+                                    void *arg, void *ext,
                                     sctp_cmd_seq_t *commands);
 
 static sctp_disposition_t sctp_sf_violation_ctsn(
@@ -3425,7 +3425,7 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
        addr_param = (union sctp_addr_param *)hdr->params;
        length = ntohs(addr_param->p.length);
        if (length < sizeof(sctp_paramhdr_t))
-               return sctp_sf_violation_paramlen(ep, asoc, type,
+               return sctp_sf_violation_paramlen(ep, asoc, type, arg,
                           (void *)addr_param, commands);
 
        /* Verify the ASCONF chunk before processing it. */
@@ -3433,8 +3433,8 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
                            (sctp_paramhdr_t *)((void *)addr_param + length),
                            (void *)chunk->chunk_end,
                            &err_param))
-               return sctp_sf_violation_paramlen(ep, asoc, type,
-                                                 (void *)&err_param, commands);
+               return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+                                                 (void *)err_param, commands);
 
        /* ADDIP 5.2 E1) Compare the value of the serial number to the value
         * the endpoint stored in a new association variable
@@ -3542,8 +3542,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
            (sctp_paramhdr_t *)addip_hdr->params,
            (void *)asconf_ack->chunk_end,
            &err_param))
-               return sctp_sf_violation_paramlen(ep, asoc, type,
-                          (void *)&err_param, commands);
+               return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+                          (void *)err_param, commands);
 
        if (last_asconf) {
                addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr;
@@ -4240,12 +4240,38 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
-                                    void *arg,
-                                    sctp_cmd_seq_t *commands) {
-       static const char err_str[] = "The following parameter had invalid length:";
+                                    void *arg, void *ext,
+                                    sctp_cmd_seq_t *commands)
+{
+       struct sctp_chunk *chunk =  arg;
+       struct sctp_paramhdr *param = ext;
+       struct sctp_chunk *abort = NULL;
 
-       return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
-                                       sizeof(err_str));
+       if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
+               goto discard;
+
+       /* Make the abort chunk. */
+       abort = sctp_make_violation_paramlen(asoc, chunk, param);
+       if (!abort)
+               goto nomem;
+
+       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+       SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+
+       sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+                       SCTP_ERROR(ECONNABORTED));
+       sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+                       SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION));
+       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+
+discard:
+       sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
+
+       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+
+       return SCTP_DISPOSITION_ABORT;
+nomem:
+       return SCTP_DISPOSITION_NOMEM;
 }
 
 /* Handle a protocol violation when the peer trying to advance the
index ac25b4c..dc50f1e 100644 (file)
@@ -27,10 +27,14 @@ static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
                - skb_headroom(skb);
        int ntail = dst->dev->needed_tailroom - skb_tailroom(skb);
 
-       if (nhead > 0 || ntail > 0)
-               return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
-
-       return 0;
+       if (nhead <= 0) {
+               if (ntail <= 0)
+                       return 0;
+               nhead = 0;
+       } else if (ntail < 0)
+               ntail = 0;
+
+       return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
 }
 
 static int xfrm_output_one(struct sk_buff *skb, int err)