Fabian Knittel wrote: > I've attached a diff containing all changes introduced by the > current patch-set.
Thanks for doing this. It makes review so much easier. > +++ b/configure.ac > @@ -212,6 +212,12 @@ AC_ARG_ENABLE(selinux, > [SELINUX="yes"] > ) > > +AC_ARG_ENABLE(vlan-tagging, > + [ --disable-vlan-tagging Disable support for VLAN tagging/untagging], > + [VLAN_TAGGING="$enableval"], > + [VLAN_TAGGING="yes"] > +) Maybe explicitly mention that it's 802.1Q ? > +dnl enable --vlan-tagging > +if test "$VLAN_TAGGING" = "yes"; then > + AC_DEFINE(ENABLE_VLAN_TAGGING, 1, [Enable VLAN tagging/untagging]) > +fi Maybe also here. > +++ b/mroute.c > @@ -164,12 +164,28 @@ mroute_extract_addr_ipv4 (struct mroute_addr *src, > return ret; > } > > +static void mroute_copy_ether_to_addr(struct mroute_addr *maddr, > + const uint8_t *eth_addr, > + int16_t vid) > +{ > + maddr->type = MR_ADDR_ETHER; > + maddr->netbits = 0; > + memcpy (maddr->addr, eth_addr, 6); > +#ifdef ENABLE_VLAN_TAGGING > + maddr->len = 8; > + memcpy (maddr->addr + 6, &vid, 2); Does this need to consider htons() ? Also, I have a weak preference for uint16_t, just to indicate that negative values are never correct. > @@ -303,6 +322,9 @@ mroute_addr_print_ex (const struct mroute_addr *ma, > { > case MR_ADDR_ETHER: > buf_printf (&out, "%s", format_hex_ex (ma->addr, 6, 0, 1, ":", gc)); > +#ifdef ENABLE_VLAN_TAGGING > + buf_printf (&out, "@%d", *(int16_t*)(ma->addr + 6)); > +#endif Also here, ntohs() ? > +++ b/multi.c .. > @@ -1918,6 +1924,28 @@ multi_process_post (struct multi_context *m, struct > multi_instance *mi, const un > return ret; > } > > +#ifdef ENABLE_VLAN_TAGGING > +bool > +buf_filter_incoming_vlan_tags (const struct buffer *buf) > +{ > + if (BLEN (buf) >= (int) sizeof (struct openvpn_8021qhdr)) > + { > + const struct openvpn_8021qhdr *vlanhdr = (const struct > openvpn_8021qhdr *) BPTR (buf); > + > + if (ntohs (vlanhdr->tpid) == OPENVPN_ETH_P_8021Q) > + { > + const int16_t vid = vlanhdr_get_vid(vlanhdr); > + if (vid != 0) > + { > + msg (D_VLAN_DEBUG, "dropping tagged incoming frame, vid: %d", > vid); > + return true; > + } > + } > + } > + return false; > +} > +#endif What a horrible coding style this is!! But oh well, that's certainly not your fault. :) However, I really like code that checks for "break" conditions first, and returns early, over code that nests multiple levels of conditions, something like: { struct openvpn_8021qhdr *vlanhdr; int16_t vid; if (BLEN (buf) < (int) sizeof (struct openvpn_8021qhdr)) return false; vlanhdr = (const struct openvpn_8021qhdr *) BPTR (buf); if (ntohs (vlanhdr->tpid) != OPENVPN_ETH_P_8021Q) return false; vid = vlanhdr_get_vid(vlanhdr); if (0 == vid) return false; msg (D_VLAN_DEBUG, "dropping .. "); return true; } But don't let this start some kind of argument about coding style. I have no technical complaints about the hunk above. > @@ -2033,10 +2062,27 @@ multi_process_incoming_link (struct multi_context *m, > struct multi_instance *ins > } > else if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TAP) > { > +#ifdef ENABLE_VLAN_TAGGING > + int16_t vid = 0; > +#else > + const int16_t vid = 0; > +#endif I like how you use const here. > @@ -2116,6 +2163,159 @@ multi_process_incoming_link (struct multi_context *m, > struct multi_instance *ins > return ret; > } > > +#ifdef ENABLE_VLAN_TAGGING > +/* > + * For vlan_accept == VAF_ONLY_UNTAGGED_OR_PRIORITY: > + * If a frame is VLAN-tagged, it is dropped. Otherwise, the global > + * vlan_pvid is returned as VID. This is just a comment in the code, but maybe mention that vid=0 in a tag does not mean that it's VLAN-tagged. Yes, _OR_PRIORITY indicates this, but it might be nice to be super consistent also in the text. > +remove_vlan_tag (const struct context *c, struct buffer *buf) > +{ .. > + /* Tagged packet. */ > + > + vid = ntohs (vlanhdr_get_vid (&vlanhdr)); Hmm - does ntohs() here mean that it shouldn't be done in mroute.c? > +multi_prepend_vlan_tag (const struct context *c, struct buffer *buf) > +{ .. > + /* Frame too small? */ > + if (BLEN (buf) < (int) sizeof (struct openvpn_ethhdr)) > + goto drop; I like forward goto for error handling very much too! > + /* Frame too small for header type? */ > + if (BLEN (buf) < (int) (sizeof (struct openvpn_8021qhdr))) > + goto drop; This looks like a whitespace oops? > + /* Not enough head room for VLAN tag? */ > + if (buf_reverse_capacity (buf) < SIZE_ETH_TO_8021Q_HDR) > + goto drop; Here too? Hmm. Am I missing something? > @@ -2158,6 +2363,16 @@ multi_process_incoming_tun (struct multi_context *m, > const unsigned int mpp_flag > * the appropriate multi_instance object. > */ > > +#ifdef ENABLE_VLAN_TAGGING > + if (dev_type == DEV_TYPE_TAP && m->top.options.vlan_tagging) > + { > + if ((vid = remove_vlan_tag (&m->top, &m->top.c2.buf)) == -1) > + { > + return false; > + } > + } > +#endif This indent also looks off - but it may just be me not knowing the coding style. (I hope not though, this is horrible.) > @@ -415,6 +418,26 @@ multi_process_outgoing_tun (struct multi_context *m, > const unsigned int mpp_flag .. > + if (m->top.options.vlan_pvid != mi->context.options.vlan_pvid) > + { Again with the weird indenting. > +++ b/openvpn.8 .. > +Incoming untagged packets from clients are assigned with the client's Port > +VLAN Identifier (PVID) as their VID. In > +.B untagged > +mode, incoming untagged packets on the tap device are associated with the > +global > +.B \-\-vlan\-pvid > +setting. In > +.B tagged > +mode, any incoming untagged packets are dropped. Would it be desirable to support both tagged and untagged at once? On Linux maybe there could be a workaround involving a bridge or so. > +++ b/options.c > @@ -1742,6 +1774,17 @@ options_postprocess_verify_ce (const struct options > *options, const struct conne > > if ((options->ssl_flags & SSLF_NO_NAME_REMAPPING) && script_method == > SM_SYSTEM) > msg (M_USAGE, "--script-security method='system' cannot be combined > with --no-name-remapping"); > +#ifdef ENABLE_VLAN_TAGGING > + if (options->vlan_tagging && dev != DEV_TYPE_TAP) > + msg (M_USAGE, "--vlan-tagging must be used with --dev tap"); > + if (!options->vlan_tagging) > + { > + if (options->vlan_accept != defaults.vlan_accept) > + msg (M_USAGE, "--vlan-accept requires --vlan-tagging"); > + if (options->vlan_pvid != defaults.vlan_pvid) > + msg (M_USAGE, "--vlan-pvid requires --vlan-tagging"); > + } > +#endif Funky indent again. > @@ -1788,7 +1831,10 @@ options_postprocess_verify_ce (const struct options > *options, const struct conne > if (options->port_share_host || options->port_share_port) > msg (M_USAGE, "--port-share requires TCP server mode (--mode server > --proto tcp-server)"); > #endif > - > +#ifdef ENABLE_VLAN_TAGGING > + if (options->vlan_tagging) > + msg (M_USAGE, "--vlan-tagging requires --mode server"); > +#endif Here too. > @@ -5730,6 +5776,45 @@ add_option (struct options *options, .. > + else if (streq (p[0], "vlan-accept") && p[1]) > + { > + VERIFY_PERMISSION (OPT_P_GENERAL); > + if (streq (p[1], "tagged")) > + { > + options->vlan_accept = VAF_ONLY_VLAN_TAGGED; > + } > + else if (streq (p[1], "untagged")) > + { > + options->vlan_accept = VAF_ONLY_UNTAGGED_OR_PRIORITY; > + } > + else if (streq (p[1], "all")) > + { > + options->vlan_accept = VAF_ALL; > + } > + else > + { > + msg (msglevel, "--vlan-accept must be 'tagged', 'untagged' or 'all'"); > + goto err; > + } > + } > + else if (streq (p[0], "vlan-pvid") && p[1]) > + { > + VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_INSTANCE); > + options->vlan_pvid = positive_atoi (p[1]); > + if (options->vlan_pvid < OPENVPN_8021Q_MIN_VID || > + options->vlan_pvid > OPENVPN_8021Q_MAX_VID) > + { > + msg (msglevel, "the parameter of --vlan-pvid parameters must be >= %d > and <= %d", OPENVPN_8021Q_MIN_VID, OPENVPN_8021Q_MAX_VID); > + goto err; > + } > + } This indent stuff is really killing me. I find it extremely hard to read. :) > +++ b/proto.c > @@ -54,6 +54,9 @@ is_ipv4 (int tunnel_type, struct buffer *buf) > return false; > eh = (const struct openvpn_ethhdr *) BPTR (buf); > if (ntohs (eh->proto) == OPENVPN_ETH_P_8021Q) { > + if (BLEN (buf) < (int)(sizeof (struct openvpn_8021qhdr) > + + sizeof (struct openvpn_iphdr))) > + return false; > const struct openvpn_8021qhdr *evh; > evh = (const struct openvpn_8021qhdr *) BPTR (buf); > if (ntohs (evh->proto) != OPENVPN_ETH_P_IPV4) Indenting here too. And I think the if needs to go after the struct to compile very broadly, even if C99 permits variables like this. > +++ b/proto.h .. > +/* > + * Retrieve the Priority Code Point (PCP) from the IEEE 802.1Q header. > + */ > +static inline int > +vlanhdr_get_pcp (const struct openvpn_8021qhdr *hdr) > +{ > + return hdr->pcp_cfi_vid & OPENVPN_8021Q_MASK_PCP; > +} What about byte order for these guys? Is it OK to use host byte order? Thank you so much for your work on this! //Peter