summaryrefslogtreecommitdiffstats
path: root/usr.sbin/switchd/ofp.c
diff options
context:
space:
mode:
authorrzalamena <rzalamena@openbsd.org>2016-12-02 14:39:46 +0000
committerrzalamena <rzalamena@openbsd.org>2016-12-02 14:39:46 +0000
commita8681f251bb7022cf719e7175e7d6195db948e24 (patch)
tree6336ad93c3f8a22f03c203d0a79346eb3b53e5bc /usr.sbin/switchd/ofp.c
parentAssert that rt_match() is always called at IPL_SOFTNET rather than (diff)
downloadwireguard-openbsd-a8681f251bb7022cf719e7175e7d6195db948e24.tar.xz
wireguard-openbsd-a8681f251bb7022cf719e7175e7d6195db948e24.zip
Implement the connection state machine for OpenFlow 1.0 and 1.3 to detect
invalid state transitions and invalid protocol version switching after the hello messages exchange. ok reyk@
Diffstat (limited to 'usr.sbin/switchd/ofp.c')
-rw-r--r--usr.sbin/switchd/ofp.c80
1 files changed, 76 insertions, 4 deletions
diff --git a/usr.sbin/switchd/ofp.c b/usr.sbin/switchd/ofp.c
index 02fd26ab16e..bce8941c557 100644
--- a/usr.sbin/switchd/ofp.c
+++ b/usr.sbin/switchd/ofp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofp.c,v 1.16 2016/11/22 17:21:56 rzalamena Exp $ */
+/* $OpenBSD: ofp.c,v 1.17 2016/12/02 14:39:46 rzalamena Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -132,10 +132,21 @@ ofp_input(struct switch_connection *con, struct ibuf *ibuf)
return (-1);
}
- if (con->con_version != OFP_V_0 &&
+ /* Check for message version match. */
+ if (con->con_state > OFP_STATE_HELLO_WAIT &&
+ con->con_version != OFP_V_0 &&
oh->oh_version != con->con_version) {
- log_debug("wrong version %d, expected %d",
- oh->oh_version, con->con_version);
+ log_debug("wrong version %s, expected %s",
+ print_map(oh->oh_version, ofp_v_map),
+ print_map(con->con_version, ofp_v_map));
+ return (-1);
+ }
+
+ /* Check the state machine to decide whether or not to allow. */
+ if (con->con_state <= OFP_STATE_HELLO_WAIT &&
+ oh->oh_type > OFP_T_ERROR) {
+ log_debug("expected hello, got %s",
+ print_map(oh->oh_type, ofp_t_map));
return (-1);
}
@@ -177,6 +188,9 @@ ofp_open(struct privsep *ps, struct switch_connection *con)
if (ofp_send_hello(ps->ps_env, con, OFP_V_1_3) == -1)
return (-1);
+ if (ofp_nextstate(ps->ps_env, con, OFP_STATE_HELLO_WAIT) == -1)
+ return (-1);
+
return (0);
}
@@ -185,3 +199,61 @@ ofp_close(struct switch_connection *con)
{
ofrelay_close(con);
}
+
+int
+ofp_nextstate(struct switchd *sc, struct switch_connection *con,
+ enum ofp_state state)
+{
+ int rv = 0;
+
+ switch (con->con_state) {
+ case OFP_STATE_CLOSED:
+ if (state != OFP_STATE_HELLO_WAIT)
+ return (-1);
+
+ break;
+
+ case OFP_STATE_HELLO_WAIT:
+ if (state != OFP_STATE_FEATURE_WAIT)
+ return (-1);
+
+ rv = ofp_send_featuresrequest(sc, con);
+ break;
+
+ case OFP_STATE_FEATURE_WAIT:
+ if (state != OFP_STATE_ESTABLISHED)
+ return (-1);
+
+ if (con->con_version != OFP_V_1_3)
+ break;
+
+#if 0
+ /* Let's not ask this while we don't use it. */
+ ofp13_flow_stats(sc, con, OFP_PORT_ANY, OFP_GROUP_ID_ANY,
+ OFP_TABLE_ID_ALL);
+ ofp13_table_features(sc, con, 0);
+ ofp13_desc(sc, con);
+#endif
+ rv |= ofp13_setconfig(sc, con, OFP_CONFIG_FRAG_NORMAL,
+ OFP_CONTROLLER_MAXLEN_NO_BUFFER);
+
+ /* Use table '0' for switch(4) and '100' for HP 3800. */
+ rv |= ofp13_tablemiss_sendctrl(sc, con, 0);
+ break;
+
+
+ case OFP_STATE_ESTABLISHED:
+ if (state != OFP_STATE_CLOSED)
+ return (-1);
+
+ break;
+
+ default:
+ return (-1);
+ }
+
+ /* Set the next state. */
+ con->con_state = state;
+
+ return (rv);
+}