+ if (mutable->out_key || (mutable->flags & TNL_F_OUT_KEY_ACTION)) {
+ struct capwaphdr_wsi *wsi = (struct capwaphdr_wsi *)(cwh + 1);
+
+ cwh->begin = CAPWAP_KEYED;
+
+ /* -1 for wsi_len byte, not included in length as per spec */
+ wsi->wsi_len = sizeof(struct capwaphdr_wsi) - 1
+ + sizeof(struct capwaphdr_wsi_key);
+ wsi->flags = CAPWAP_WSI_F_KEY64;
+ wsi->reserved_padding = 0;
+
+ if (mutable->out_key) {
+ struct capwaphdr_wsi_key *opt = (struct capwaphdr_wsi_key *)(wsi + 1);
+ opt->key = mutable->out_key;
+ }
+ } else {
+ /* make packet readable by old capwap code */
+ cwh->begin = CAPWAP_NO_WSI;
+ }
+}
+
+static struct sk_buff *capwap_update_header(const struct vport *vport,
+ const struct tnl_mutable_config *mutable,
+ struct dst_entry *dst,
+ struct sk_buff *skb)
+{
+ struct udphdr *udph = udp_hdr(skb);
+
+ if (mutable->flags & TNL_F_OUT_KEY_ACTION) {
+ /* first field in WSI is key */
+ struct capwaphdr *cwh = (struct capwaphdr *)(udph + 1);
+ struct capwaphdr_wsi *wsi = (struct capwaphdr_wsi *)(cwh + 1);
+ struct capwaphdr_wsi_key *opt = (struct capwaphdr_wsi_key *)(wsi + 1);
+
+ opt->key = OVS_CB(skb)->tun_id;
+ }
+
+ udph->len = htons(skb->len - skb_transport_offset(skb));
+
+ if (unlikely(skb->len - skb_network_offset(skb) > dst_mtu(dst))) {
+ unsigned int hlen = skb_transport_offset(skb) + capwap_hdr_len(mutable);
+ skb = fragment(skb, vport, dst, hlen);
+ }