+static int
+send_openflow_buffer(struct ofpbuf *buffer)
+{
+ int retval;
+
+ if (!mgmt_rconn) {
+ VLOG_ERR("attempt to send openflow packet with no rconn\n");
+ return EINVAL;
+ }
+
+ /* Make sure there's room to transmit the data. We don't want to
+ * fail part way through a send. */
+ if (rconn_packet_counter_read(txqlen) >= TXQ_LIMIT) {
+ return EAGAIN;
+ }
+
+ /* OpenFlow messages use a 16-bit length field, so messages over 64K
+ * must be broken into multiple pieces.
+ */
+ if (buffer->size <= 65535) {
+ update_openflow_length(buffer);
+ retval = rconn_send(mgmt_rconn, buffer, txqlen);
+ if (retval) {
+ VLOG_WARN_RL(&rl, "send to %s failed: %s",
+ rconn_get_name(mgmt_rconn), strerror(retval));
+ }
+ return retval;
+ } else {
+ struct ofmp_header *header = (struct ofmp_header *)buffer->data;
+ uint32_t xid = header->header.header.xid;
+ size_t remain = buffer->size;
+ uint8_t *ptr = buffer->data;
+
+ /* Mark the OpenFlow header with a zero length to indicate some
+ * funkiness.
+ */
+ header->header.header.length = 0;
+
+ while (remain > 0) {
+ struct ofpbuf *new_buffer;
+ struct ofmp_extended_data *oed;
+ size_t new_len = MIN(65535 - sizeof *oed, remain);
+
+ oed = make_ofmp_xid(sizeof *oed, OFMPT_EXTENDED_DATA, xid,
+ &new_buffer);
+ oed->type = header->type;
+
+ if (remain > new_len) {
+ oed->flags |= OFMPEDF_MORE_DATA;
+ }
+
+ /* Copy the entire original message, including the OpenFlow
+ * header, since management protocol structure definitions
+ * include these headers.
+ */
+ ofpbuf_put(new_buffer, ptr, new_len);
+
+ update_openflow_length(new_buffer);
+ retval = rconn_send(mgmt_rconn, new_buffer, txqlen);
+ if (retval) {
+ VLOG_WARN_RL(&rl, "send to %s failed: %s",
+ rconn_get_name(mgmt_rconn), strerror(retval));
+ ofpbuf_delete(buffer);
+ return retval;
+ }
+
+ remain -= new_len;
+ ptr += new_len;
+ }
+
+ ofpbuf_delete(buffer);
+ return 0;
+ }
+}
+
+static void
+send_features_reply(uint32_t xid)
+{
+ struct ofpbuf *buffer;
+ struct ofp_switch_features *ofr;
+
+ ofr = make_openflow_xid(sizeof *ofr, OFPT_FEATURES_REPLY, xid, &buffer);
+ ofr->datapath_id = 0;
+ ofr->n_tables = 0;
+ ofr->n_buffers = 0;
+ ofr->capabilities = 0;
+ ofr->actions = 0;
+ send_openflow_buffer(buffer);
+}
+