/* alternative VLAN for IP session 0 if not untagged */ #define MBIM_IPS0_VID 4094
/* driver specific data - must match cdc_ncm usage */ struct cdc_mbim_state { struct cdc_ncm_ctx *ctx;
atomic_t pmcount; struct usb_driver *subdriver; unsignedlong _unused; unsignedlong flags;
};
/* flags for the cdc_mbim_state.flags field */ enum cdc_mbim_flags {
FLAG_IPS0_VLAN = 1 << 0, /* IP session 0 is tagged */
};
/* using a counter to merge subdriver requests with our own into a combined state */ staticint cdc_mbim_manage_power(struct usbnet *dev, int on)
{ struct cdc_mbim_state *info = (void *)&dev->data; int rv = 0;
if ((on && atomic_add_return(1, &info->pmcount) == 1) || (!on && atomic_dec_and_test(&info->pmcount))) { /* need autopm_get/put here to ensure the usbcore sees the new value */
rv = usb_autopm_get_interface(dev->intf);
dev->intf->needs_remote_wakeup = on; if (!rv)
usb_autopm_put_interface(dev->intf);
} return0;
}
/* creation of this VLAN is a request to tag IP session 0 */ if (vid == MBIM_IPS0_VID)
info->flags |= FLAG_IPS0_VLAN; else if (vid >= 512) /* we don't map these to MBIM session */ return -EINVAL; return0;
}
/* should we change control altsetting on a NCM/MBIM function? */ if (cdc_ncm_select_altsetting(intf) == CDC_NCM_COMM_ALTSETTING_MBIM) {
data_altsetting = CDC_NCM_DATA_ALTSETTING_MBIM;
ret = cdc_mbim_set_ctrlalt(dev, intf, CDC_NCM_COMM_ALTSETTING_MBIM); if (ret) goto err;
ret = -ENODEV;
}
/* we will hit this for NCM/MBIM functions if prefer_mbim is false */ if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) goto err;
ret = cdc_ncm_bind_common(dev, intf, data_altsetting, dev->driver_info->data); if (ret) goto err;
ctx = info->ctx;
/* The MBIM descriptor and the status endpoint are required */ if (ctx->mbim_desc && dev->status)
subdriver = usb_cdc_wdm_register(ctx->control,
&dev->status->desc,
le16_to_cpu(ctx->mbim_desc->wMaxControlMessage),
WWAN_PORT_MBIM,
cdc_mbim_wdm_manage_power); if (IS_ERR(subdriver)) {
ret = PTR_ERR(subdriver);
cdc_ncm_unbind(dev, intf); goto err;
}
/* can't let usbnet use the interrupt endpoint */
dev->status = NULL;
info->subdriver = subdriver;
/* MBIM cannot do ARP */
dev->net->flags |= IFF_NOARP;
/* no need to put the VLAN tci in the packet headers */
dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_FILTER;
/* disconnect subdriver from control interface */ if (info->subdriver && info->subdriver->disconnect)
info->subdriver->disconnect(ctx->control);
info->subdriver = NULL;
/* let NCM unbind clean up both control and data interface */
cdc_ncm_unbind(dev, intf);
}
/* verify that the ethernet protocol is IPv4 or IPv6 */ staticbool is_ip_proto(__be16 proto)
{ switch (proto) { case htons(ETH_P_IP): case htons(ETH_P_IPV6): returntrue;
} returnfalse;
}
/* Some applications using e.g. packet sockets will *bypasstheVLANaccelerationandcreatetagged *ethernetframesdirectly.Weprimarilylookfor *theacceleratedout-of-bandtag,butfallbackif *required
*/
skb_reset_mac_header(skb); if (vlan_get_tag(skb, &tci) < 0 && skb->len > VLAN_ETH_HLEN &&
__vlan_get_tag(skb, &tci) == 0) {
is_ip = is_ip_proto(vlan_eth_hdr(skb)->h_vlan_encapsulated_proto);
skb_pull(skb, VLAN_ETH_HLEN);
} else {
is_ip = is_ip_proto(eth_hdr(skb)->h_proto);
skb_pull(skb, ETH_HLEN);
}
/* Is IP session <0> tagged too? */ if (info->flags & FLAG_IPS0_VLAN) { /* drop all untagged packets */ if (!tci) goto error; /* map MBIM_IPS0_VID to IPS<0> */ if (tci == MBIM_IPS0_VID)
tci = 0;
}
/* Some devices are known to send Neighbor Solicitation messages and *requireNeighborAdvertisementreplies.TheIPv6corewillnot *respondsinceIFF_NOARPisset,sowemusthandlethemourselves.
*/ staticvoid do_neigh_solicit(struct usbnet *dev, u8 *buf, u16 tci)
{ struct ipv6hdr *iph = (void *)buf; struct nd_msg *msg = (void *)(iph + 1); struct net_device *netdev; struct inet6_dev *in6_dev; bool is_router;
/* we'll only respond to requests from unicast addresses to *oursolicitednodeaddresses.
*/ if (!ipv6_addr_is_solict_mult(&iph->daddr) ||
!(ipv6_addr_type(&iph->saddr) & IPV6_ADDR_UNICAST)) return;
/* need to send the NA on the VLAN dev, if any */
rcu_read_lock(); if (tci) {
netdev = __vlan_find_dev_deep_rcu(dev->net, htons(ETH_P_8021Q),
tci); if (!netdev) {
rcu_read_unlock(); return;
}
} else {
netdev = dev->net;
}
dev_hold(netdev);
rcu_read_unlock();
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.10Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.