summaryrefslogtreecommitdiff
path: root/chips/nc.c
diff options
context:
space:
mode:
authorThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
committerThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
commitf07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch)
tree12b07c7e578fc1a5f53dbfde2632408491ff2a70 /chips/nc.c
Initial source
Diffstat (limited to 'chips/nc.c')
-rw-r--r--chips/nc.c851
1 files changed, 851 insertions, 0 deletions
diff --git a/chips/nc.c b/chips/nc.c
new file mode 100644
index 0000000..adce0ae
--- /dev/null
+++ b/chips/nc.c
@@ -0,0 +1,851 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*** NETWORK INTERFACE IMPLEMENTATION CORE ***/
+
+#ifndef STUB
+#include <chips/nc.h>
+#else
+#include "nc.h"
+#endif
+
+/*** Types and data structures ***/
+
+#if PRODUCTION
+#define MAX_HASH 701
+#define MAX_HOST 4000
+#else
+#define MAX_HASH 7
+#define MAX_HOST 4
+#endif
+
+nw_dev_entry_s nc_failure_entry_table = {nc_fail, nc_fail,
+ nc_null, nc_null,
+ nc_null_poll, nc_null_send, nc_null_rpc,
+ nc_null_signal, nc_open_fail, nc_accept_fail,
+ nc_close_fail, nc_open_fail, nc_open_fail};
+
+nw_dev_entry_s nc_local_entry_table = {nc_succeed, nc_succeed,
+ nc_null, nc_null,
+ nc_null_poll, nc_local_send, nc_local_rpc,
+ nc_null_signal, nc_open_fail, nc_accept_fail,
+ nc_close_fail, nc_open_fail, nc_open_fail};
+
+
+typedef struct {
+ nw_address_s address;
+ int name_next:16;
+ int ip_next:16;
+ int nw_next:16;
+ nw_ep line:16;
+} nw_alist_s, *nw_alist_t;
+
+
+boolean_t nc_initialized = FALSE;
+nw_tx_header_s nw_tx[MAX_EP/2];
+nw_tx_header_t nw_free_tx_header;
+nw_rx_header_s nw_rx[2*MAX_EP];
+nw_rx_header_t nw_free_rx_header;
+nw_plist_s nw_peer[MAX_EP];
+nw_plist_t nw_free_peer;
+
+nw_devcb devct[MAX_DEV];
+
+nw_ecb ect[MAX_EP];
+
+int nw_free_ep_first, nw_free_ep_last;
+int nw_free_line_first, nw_free_line_last;
+
+nw_alist_s nw_address[MAX_HOST];
+int nw_free_address;
+
+int nw_name[MAX_HASH];
+int nw_ip[MAX_HASH];
+int nw_nw[MAX_HASH];
+
+int nw_fast_req;
+
+/*** System-independent functions ***/
+
+void nc_initialize() {
+ int ep, last_ep;
+
+ if (!nc_initialized) {
+ last_ep = sizeof(nw_tx)/sizeof(nw_tx_header_s) - 1;
+ for (ep = 0; ep < last_ep; ep++)
+ nw_tx[ep].next = &nw_tx[ep+1];
+ nw_tx[last_ep].next = NULL;
+ nw_free_tx_header = &nw_tx[0];
+ last_ep = sizeof(nw_rx)/sizeof(nw_rx_header_s) - 1;
+ for (ep = 0; ep < last_ep; ep++)
+ nw_rx[ep].next = &nw_rx[ep+1];
+ nw_rx[last_ep].next = NULL;
+ nw_free_rx_header = &nw_rx[0];
+ last_ep = sizeof(nw_peer)/sizeof(nw_plist_s) - 1;
+ for (ep = 0; ep < last_ep; ep++)
+ nw_peer[ep].next = &nw_peer[ep+1];
+ nw_peer[last_ep].next = NULL;
+ nw_free_peer = &nw_peer[0];
+ for (ep = 0; ep < MAX_DEV; ep++) {
+ devct[ep].status = NW_FAILURE;
+ devct[ep].type = NW_CONNECTIONLESS;
+ devct[ep].addr = NULL;
+ devct[ep].local_addr_1 = 0;
+ devct[ep].local_addr_2 = 0;
+ devct[ep].entry = &nc_failure_entry_table;
+ devct[ep].fast_req = 0;
+ }
+ devct[NW_NULL].status = NW_SUCCESS;
+ devct[NW_NULL].entry = &nc_local_entry_table;
+ last_ep = sizeof(ect)/sizeof(nw_ecb);
+ for (ep = 0; ep < last_ep; ep++) {
+ ect[ep].state = NW_INEXISTENT;
+ ect[ep].id = ep;
+ ect[ep].seqno = 0;
+ ect[ep].previous = ep - 1;
+ ect[ep].next = ep + 1;
+ }
+ ect[0].next = ect[0].previous = 0;
+ ect[last_ep-1].next = 0;
+ nw_free_ep_first = 1;
+ nw_free_ep_last = last_ep - 1;
+ nw_free_line_first = nw_free_line_last = 0;
+ for (ep = 0; ep < MAX_HOST; ep++) {
+ nw_address[ep].nw_next = ep + 1;
+ }
+ nw_address[MAX_HOST - 1].nw_next = -1;
+ nw_free_address = 0;
+ for (ep = 0; ep < MAX_HASH; ep++) {
+ nw_name[ep] = -1;
+ nw_ip[ep] = -1;
+ nw_nw[ep] = -1;
+ }
+ nw_fast_req = 0;
+ h_initialize();
+ nc_initialized = TRUE;
+ }
+}
+
+nw_tx_header_t nc_tx_header_allocate() {
+ nw_tx_header_t header;
+
+ header = nw_free_tx_header;
+ if (header != NULL)
+ nw_free_tx_header = header->next;
+ return header;
+}
+
+void nc_tx_header_deallocate(nw_tx_header_t header) {
+ nw_tx_header_t first_header;
+
+ first_header = header;
+ while (header->next != NULL)
+ header = header->next;
+ header->next = nw_free_tx_header;
+ nw_free_tx_header = first_header;
+}
+
+nw_rx_header_t nc_rx_header_allocate() {
+ nw_rx_header_t header;
+
+ header = nw_free_rx_header;
+ if (header != NULL)
+ nw_free_rx_header = header->next;
+ return header;
+}
+
+void nc_rx_header_deallocate(nw_rx_header_t header) {
+
+ header->next = nw_free_rx_header;
+ nw_free_rx_header = header;
+}
+
+nw_plist_t nc_peer_allocate() {
+ nw_plist_t peer;
+
+ peer = nw_free_peer;
+ if (peer != NULL)
+ nw_free_peer = peer->next;
+ return peer;
+}
+
+void nc_peer_deallocate(nw_plist_t peer) {
+ nw_plist_t first_peer;
+
+ first_peer = peer;
+ while (peer->next != NULL)
+ peer = peer->next;
+ peer->next = nw_free_peer;
+ nw_free_peer = first_peer;
+}
+
+
+nw_result nc_device_register(u_int dev, nw_dev_type type, char *dev_addr,
+ nw_dev_entry_t dev_entry_table) {
+ nw_result rc;
+
+ if (dev >= MAX_DEV) {
+ rc = NW_FAILURE;
+ } else {
+ devct[dev].status = NW_SUCCESS;
+ devct[dev].type = type;
+ devct[dev].addr = dev_addr;
+ devct[dev].entry = dev_entry_table;
+ devct[dev].fast_req = 0;
+ rc = NW_SUCCESS;
+ }
+ return rc;
+}
+
+nw_result nc_device_unregister(u_int dev, nw_result status) {
+ nw_result rc;
+
+ if (dev >= MAX_DEV) {
+ rc = NW_FAILURE;
+ } else {
+ devct[dev].status = status;
+ devct[dev].addr = NULL;
+ devct[dev].entry = &nc_failure_entry_table;
+ devct[dev].fast_req = 0;
+ rc = NW_SUCCESS;
+ }
+ return rc;
+}
+
+void nc_slow_sweep() {
+ int dev;
+
+ for (dev = 0; dev < MAX_DEV; dev++) {
+ if (devct[dev].status == NW_SUCCESS) {
+ (*(devct[dev].entry->slow_sweep)) (dev);
+ }
+ }
+}
+
+void nc_fast_timer_set(int dev) {
+
+ devct[dev].fast_req++;
+ if (nw_fast_req++ == 0)
+ h_fast_timer_set();
+}
+
+void nc_fast_timer_reset(int dev) {
+
+ devct[dev].fast_req--;
+ if (nw_fast_req-- == 0)
+ h_fast_timer_reset();
+}
+
+
+void nc_fast_sweep() {
+ int dev;
+
+ for (dev = 0; dev < MAX_DEV; dev++) {
+ if (devct[dev].status == NW_SUCCESS &&
+ devct[dev].fast_req > 0) {
+ devct[dev].fast_req = 0;
+ (*(devct[dev].entry->fast_sweep)) (dev);
+ }
+ }
+}
+
+int nc_hash_name(char *cp) {
+ int h;
+ char ch;
+ char *cp_end;
+
+ cp_end = cp + 19;
+ *cp_end = '\0';
+ h = 0;
+ ch = *cp++;
+ while (ch != '\0') {
+ h = (h << 7) + ch;
+ ch = *cp++;
+ if (ch != '\0') {
+ h = (h << 7) + ch;
+ ch = *cp++;
+ if (ch != '\0') {
+ h = (h << 7) + ch;
+ ch = *cp++;
+ }
+ }
+ h %= MAX_HASH;
+ }
+ return h;
+}
+
+
+nw_result nc_update(nw_update_type up_type, int *up_info) {
+ nw_result rc;
+ nw_alist_t ad;
+ int h, slot, previous_slot, found_slot;
+ nw_address_1 n1;
+ nw_address_2 n2;
+
+ if (up_type == NW_HOST_ADDRESS_REGISTER) {
+ if (nw_free_address == -1) {
+ rc = NW_NO_RESOURCES;
+ } else {
+ slot = nw_free_address;
+ ad = &nw_address[slot];
+ nw_free_address = ad->nw_next;
+ ad->address = *((nw_address_t) up_info);
+ h = nc_hash_name(ad->address.name);
+ ad->name_next = nw_name[h];
+ nw_name[h] = slot;
+ h = ad->address.ip_addr % MAX_HASH;
+ ad->ip_next = nw_ip[h];
+ nw_ip[h] = slot;
+ h = (ad->address.nw_addr_1 % MAX_HASH + ad->address.nw_addr_2)
+ % MAX_HASH;
+ ad->nw_next = nw_nw[h];
+ nw_nw[h] = slot;
+ ad->line = 0;
+ rc = NW_SUCCESS;
+ }
+ } else if (up_type == NW_HOST_ADDRESS_UNREGISTER) {
+ n1 = ((nw_address_t) up_info)->nw_addr_1;
+ n2 = ((nw_address_t) up_info)->nw_addr_2;
+ h = (n1 % MAX_HASH + n2) % MAX_HASH;
+ slot = nw_nw[h];
+ previous_slot = -1;
+ ad = &nw_address[slot];
+ while (slot != -1 && (ad->address.nw_addr_1 != n1 ||
+ ad->address.nw_addr_2 != n2)) {
+ previous_slot = slot;
+ slot = ad->nw_next;
+ ad = &nw_address[slot];
+ }
+ if (slot == -1) {
+ rc = NW_BAD_ADDRESS;
+ } else {
+ if (previous_slot == -1)
+ nw_nw[h] = ad->nw_next;
+ else
+ nw_address[previous_slot].nw_next = ad->nw_next;
+ ad->nw_next = nw_free_address;
+ nw_free_address = slot;
+ found_slot = slot;
+ if (ad->address.ip_addr != 0) {
+ h = ad->address.ip_addr % MAX_HASH;
+ slot = nw_ip[h];
+ previous_slot = -1;
+ while (slot != -1 && slot != found_slot) {
+ previous_slot = slot;
+ slot = nw_address[slot].ip_next;
+ }
+ if (slot == found_slot) {
+ if (previous_slot == -1)
+ nw_ip[h] = ad->ip_next;
+ else
+ nw_address[previous_slot].ip_next = ad->ip_next;
+ }
+ }
+ if (ad->address.name[0] != '\0') {
+ h = nc_hash_name(ad->address.name);
+ slot = nw_name[h];
+ previous_slot = -1;
+ while (slot != -1 && slot != found_slot) {
+ previous_slot = slot;
+ slot = nw_address[slot].name_next;
+ }
+ if (slot == found_slot) {
+ if (previous_slot == -1)
+ nw_name[h] = ad->name_next;
+ else
+ nw_address[previous_slot].name_next = ad->name_next;
+ }
+ }
+ rc = NW_SUCCESS;
+ }
+ } else {
+ rc = NW_INVALID_ARGUMENT;
+ }
+ return rc;
+}
+
+nw_result nc_lookup(nw_lookup_type lt, int *look_info) {
+ nw_result rc;
+ nw_address_t addr;
+ nw_alist_t ad;
+ int h, slot;
+ ip_address ip;
+ nw_address_1 n1;
+ nw_address_2 n2;
+
+ if (lt == NW_HOST_ADDRESS_LOOKUP) {
+ addr = (nw_address_t) look_info;
+ if (addr->ip_addr != 0) {
+ ip = addr->ip_addr;
+ h = ip % MAX_HASH;
+ slot = nw_ip[h];
+ ad = &nw_address[slot];
+ while (slot != -1 && ad->address.ip_addr != ip) {
+ slot = ad->ip_next;
+ ad = &nw_address[slot];
+ }
+ if (slot != -1) {
+ strcpy(addr->name, ad->address.name);
+ addr->nw_addr_1 = ad->address.nw_addr_1;
+ addr->nw_addr_2 = ad->address.nw_addr_2;
+ return NW_SUCCESS;
+ }
+ }
+ if (addr->name[0] != '\0') {
+ h = nc_hash_name(addr->name);
+ slot = nw_name[h];
+ ad = &nw_address[slot];
+ while (slot != -1 && strcmp(ad->address.name, addr->name) != 0) {
+ slot = ad->name_next;
+ ad = &nw_address[slot];
+ }
+ if (slot != -1) {
+ addr->ip_addr = ad->address.ip_addr;
+ addr->nw_addr_1 = ad->address.nw_addr_1;
+ addr->nw_addr_2 = ad->address.nw_addr_2;
+ return NW_SUCCESS;
+ }
+ }
+ if (addr->nw_addr_1 != 0 || addr->nw_addr_2 != 0) {
+ n1 = addr->nw_addr_1;
+ n2 = addr->nw_addr_2;
+ h = (n1 % MAX_HASH + n2) % MAX_HASH;
+ slot = nw_nw[h];
+ ad = &nw_address[slot];
+ while (slot != -1 && (ad->address.nw_addr_1 != n1 ||
+ ad->address.nw_addr_2 != n2)) {
+ slot = ad->nw_next;
+ ad = &nw_address[slot];
+ }
+ if (slot != -1) {
+ strcpy(addr->name, ad->address.name);
+ addr->ip_addr = ad->address.ip_addr;
+ return NW_SUCCESS;
+ }
+ }
+ rc = NW_BAD_ADDRESS;
+ } else {
+ rc = NW_INVALID_ARGUMENT;
+ }
+ return rc;
+}
+
+nw_result nc_line_update(nw_peer_t peer, nw_ep line) {
+ nw_result rc;
+ nw_alist_t ad;
+ int h, slot;
+ nw_address_1 n1;
+ nw_address_2 n2;
+
+ n1 = peer->rem_addr_1;
+ n2 = peer->rem_addr_2;
+ h = (n1 % MAX_HASH + n2) % MAX_HASH;
+ slot = nw_nw[h];
+ ad = &nw_address[slot];
+ while (slot != -1 && (ad->address.nw_addr_1 != n1 ||
+ ad->address.nw_addr_2 != n2)) {
+ slot = ad->nw_next;
+ ad = &nw_address[slot];
+ }
+ if (slot == -1) {
+ rc = NW_FAILURE;
+ } else {
+ ad->line = line;
+ rc = NW_SUCCESS;
+ }
+ return rc;
+}
+
+nw_ep nc_line_lookup(nw_peer_t peer) {
+ nw_ep lep;
+ nw_alist_t ad;
+ int h, slot;
+ nw_address_1 n1;
+ nw_address_2 n2;
+
+ n1 = peer->rem_addr_1;
+ n2 = peer->rem_addr_2;
+ h = (n1 % MAX_HASH + n2) % MAX_HASH;
+ slot = nw_nw[h];
+ ad = &nw_address[slot];
+ while (slot != -1 && (ad->address.nw_addr_1 != n1 ||
+ ad->address.nw_addr_2 != n2)) {
+ slot = ad->nw_next;
+ ad = &nw_address[slot];
+ }
+ if (slot == -1) {
+ lep = -1;
+ } else {
+ lep = ad->line;
+ }
+ return lep;
+}
+
+nw_result nc_endpoint_allocate(nw_ep_t epp, nw_protocol protocol,
+ nw_acceptance accept,
+ char *buffer_address, u_int buffer_size) {
+ nw_result rc;
+ nw_ep ep;
+ nw_ecb_t ecb;
+
+ if (ect[(ep = *epp)].state != NW_INEXISTENT) {
+ rc = NW_BAD_EP;
+ } else if (nw_free_ep_first == 0) {
+ *epp = nw_free_line_first;
+ rc = NW_NO_EP;
+ } else {
+ if (ep == 0) {
+ ecb = &ect[nw_free_ep_first];
+ *epp = ep = ecb->id;
+ nw_free_ep_first = ecb->next;
+ if (nw_free_ep_first == 0)
+ nw_free_ep_last = 0;
+ } else {
+ ecb = &ect[ep];
+ if (ecb->previous == 0)
+ nw_free_ep_first = ecb->next;
+ else
+ ect[ecb->previous].next = ecb->next;
+ if (ecb->next == 0)
+ nw_free_ep_last = ecb->previous;
+ else
+ ect[ecb->next].previous = ecb->previous;
+ }
+ if (protocol == NW_LINE) {
+ if (nw_free_line_last == 0)
+ nw_free_line_first = ep;
+ else
+ ect[nw_free_line_last].next = ep;
+ ecb->previous = nw_free_line_last;
+ ecb->next = 0;
+ nw_free_line_last = ep;
+ }
+ ecb->protocol = protocol;
+ ecb->accept = accept;
+ ecb->state = NW_UNCONNECTED;
+ ecb->conn = NULL;
+ ecb->buf_start = buffer_address;
+ ecb->buf_end = buffer_address + buffer_size;
+ ecb->free_buffer = (nw_unused_buffer_t) buffer_address;
+ ecb->free_buffer->buf_used = 0;
+ ecb->free_buffer->buf_length = buffer_size;
+ ecb->free_buffer->previous = NULL;
+ ecb->free_buffer->next = NULL;
+ ecb->overrun = 0;
+ ecb->seqno = 0;
+ ecb->tx_first = NULL;
+ ecb->tx_last = NULL;
+ ecb->tx_initial = NULL;
+ ecb->tx_current = NULL;
+ ecb->rx_first = NULL;
+ ecb->rx_last = NULL;
+ rc = NW_SUCCESS;
+ }
+ return rc;
+}
+
+nw_result nc_endpoint_deallocate(nw_ep ep) {
+ nw_ecb_t ecb;
+ nw_rx_header_t rx_header;
+
+ ecb = &ect[ep];
+ if (ecb->conn != NULL)
+ nc_peer_deallocate(ecb->conn);
+ if (ecb->tx_first != NULL)
+ nc_tx_header_deallocate(ecb->tx_first);
+ if (ecb->tx_initial != NULL)
+ nc_tx_header_deallocate(ecb->tx_initial);
+ while (ecb->rx_first != NULL) {
+ rx_header = ecb->rx_first;
+ ecb->rx_first = rx_header->next;
+ nc_rx_header_deallocate(rx_header);
+ }
+ if (ecb->protocol == NW_LINE) {
+ if (ecb->previous == 0)
+ nw_free_line_first = ecb->next;
+ else
+ ect[ecb->previous].next = ecb->next;
+ if (ecb->next == 0)
+ nw_free_line_last = ecb->previous;
+ else
+ ect[ecb->next].previous = ecb->previous;
+ }
+ ecb->next = 0;
+ ecb->previous = nw_free_ep_last;
+ if (nw_free_ep_last == 0)
+ nw_free_ep_first = ep;
+ else
+ ect[nw_free_ep_last].next = ep;
+ nw_free_ep_last = ep;
+ ecb->id = ep;
+ ecb->state = NW_INEXISTENT;
+ return NW_SUCCESS;
+}
+
+void nc_buffer_coalesce(nw_ecb_t ecb) {
+ nw_unused_buffer_t p, q, buf_free, buf_start, buf_end;
+
+ buf_start = p = (nw_unused_buffer_t) ecb->buf_start;
+ buf_end = (nw_unused_buffer_t) ecb->buf_end;
+ buf_free = NULL;
+ while (p >= buf_start && p < buf_end) {
+ if (p->buf_length & 0x3)
+ goto trash_area;
+ if (p->buf_used) {
+ p = (nw_unused_buffer_t) ((char *) p + p->buf_length);
+ } else {
+ q = (nw_unused_buffer_t) ((char *) p + p->buf_length);
+ while (q >= buf_start && q < buf_end && !q->buf_used) {
+ if (q->buf_length & 0x3)
+ goto trash_area;
+ p->buf_length += q->buf_length;
+ q = (nw_unused_buffer_t) ((char *) q + q->buf_length);
+ }
+ p->next = buf_free;
+ p->previous = NULL;
+ if (buf_free != NULL)
+ buf_free->previous = p;
+ buf_free = p;
+ p = q;
+ }
+ }
+ ecb->free_buffer = buf_free;
+ return;
+
+ trash_area:
+ ecb->free_buffer = NULL;
+ return;
+}
+
+
+nw_buffer_t nc_buffer_allocate(nw_ep ep, u_int size) {
+ nw_ecb_t ecb;
+ nw_unused_buffer_t buf, buf_start, buf_end;
+
+ ecb = &ect[ep];
+ buf_start = (nw_unused_buffer_t) ecb->buf_start;
+ buf_end = (nw_unused_buffer_t) (ecb->buf_end - sizeof(nw_buffer_s));
+ if (size < sizeof(nw_buffer_s))
+ size = sizeof(nw_buffer_s);
+ else
+ size = ((size + 3) >> 2) << 2;
+ buf = ecb->free_buffer;
+ if (buf != NULL) {
+ while (buf->buf_length < size) {
+ buf = buf->next;
+ if (buf < buf_start || buf > buf_end || ((int) buf & 0x3)) {
+ buf = NULL;
+ break;
+ }
+ }
+ }
+ if (buf == NULL) {
+ nc_buffer_coalesce(ecb);
+ buf = ecb->free_buffer;
+ while (buf != NULL && buf->buf_length < size)
+ buf = buf->next;
+ }
+ if (buf == NULL) {
+ ecb->overrun = 1;
+ } else {
+ if (buf->buf_length < size + sizeof(nw_buffer_s)) {
+ if (buf->previous == NULL)
+ ecb->free_buffer = buf->next;
+ else
+ buf->previous->next = buf->next;
+ if (buf->next != NULL)
+ buf->next->previous = buf->previous;
+ } else {
+ buf->buf_length -= size;
+ buf = (nw_unused_buffer_t) ((char *) buf + buf->buf_length);
+ buf->buf_length = size;
+ }
+ buf->buf_used = 1;
+ }
+ return (nw_buffer_t) buf;
+}
+
+nw_result nc_buffer_deallocate(nw_ep ep, nw_buffer_t buffer) {
+ nw_ecb_t ecb;
+ nw_unused_buffer_t buf;
+
+ ecb = &ect[ep];
+ buf = (nw_unused_buffer_t) buffer;
+ buf->buf_used = 0;
+ buf->previous = NULL;
+ buf->next = ecb->free_buffer;
+ if (ecb->free_buffer != NULL)
+ ecb->free_buffer->previous = buf;
+ ecb->free_buffer = buf;
+ return NW_SUCCESS;
+}
+
+nw_result nc_endpoint_status(nw_ep ep, nw_state_t state, nw_peer_t peer) {
+ nw_result rc;
+ nw_ecb_t ecb;
+
+ ecb = &ect[ep];
+ *state = ecb->state;
+ if (ecb->conn)
+ *peer = ecb->conn->peer;
+ if (ecb->overrun) {
+ ecb->overrun = 0;
+ rc = NW_OVERRUN;
+ } else if (ecb->rx_first != NULL) {
+ rc = NW_QUEUED;
+ } else {
+ rc = NW_SUCCESS;
+ }
+ return rc;
+}
+
+
+nw_result nc_local_send(nw_ep ep, nw_tx_header_t header, nw_options options) {
+ nw_result rc;
+ nw_ep receiver;
+ int length;
+ nw_buffer_t buffer;
+ nw_tx_header_t first_header;
+ nw_rx_header_t rx_header;
+ char *bufp;
+ nw_ecb_t ecb;
+
+ receiver = header->peer.remote_ep;
+ length = header->msg_length;
+ buffer = nc_buffer_allocate(receiver, sizeof(nw_buffer_s) + length);
+ if (buffer == NULL) {
+ rc = NW_OVERRUN;
+ } else {
+ buffer->buf_next = NULL;
+ buffer->block_offset = sizeof(nw_buffer_s);
+ buffer->block_length = length;
+ buffer->peer.rem_addr_1 = NW_NULL << 28;
+ buffer->peer.rem_addr_2 = 0;
+ buffer->peer.remote_ep = ep;
+ buffer->peer.local_ep = receiver;
+ bufp = (char *) buffer + sizeof(nw_buffer_s);
+ first_header = header;
+ while (header != NULL) {
+ length = header->block_length;
+ bcopy(header->block, bufp, length);
+ bufp += length;
+ if (header->buffer != NULL)
+ nc_buffer_deallocate(ep, header->buffer);
+ header = header->next;
+ }
+ nc_tx_header_deallocate(first_header);
+ ecb = &ect[receiver];
+ if (options == NW_URGENT) {
+ buffer->msg_seqno = 0;
+ if (nc_deliver_result(receiver, NW_RECEIVE_URGENT, (int) buffer))
+ rc = NW_SUCCESS;
+ else
+ rc = NW_NO_RESOURCES;
+ } else {
+ if (ecb->seqno == 1023)
+ buffer->msg_seqno = ecb->seqno = 1;
+ else
+ buffer->msg_seqno = ++ecb->seqno;
+ if (nc_deliver_result(receiver, NW_RECEIVE, (int) buffer))
+ rc = NW_SUCCESS;
+ else
+ rc = NW_NO_RESOURCES;
+ }
+ }
+ return rc;
+}
+
+nw_buffer_t nc_local_rpc(nw_ep ep, nw_tx_header_t header, nw_options options) {
+ nw_buffer_t buf;
+ nw_ecb_t ecb;
+ nw_rx_header_t rx_header;
+
+ ecb = &ect[ep];
+ rx_header = ecb->rx_first;
+ if (nc_local_send(ep, header, options) != NW_SUCCESS) {
+ buf = NW_BUFFER_ERROR;
+ } else if (rx_header == NULL) {
+ buf = NULL;
+ } else {
+ buf = rx_header->buffer;
+ ecb->rx_first = rx_header->next;
+ if (ecb->rx_first == NULL)
+ ecb->rx_last = NULL;
+ nc_rx_header_deallocate(rx_header);
+ }
+ return buf;
+}
+
+
+nw_result nc_succeed(int dev) {
+
+ return NW_SUCCESS;
+}
+
+void nc_null(int dev) {
+
+}
+
+nw_result nc_fail(int dev) {
+
+ return NW_FAILURE;
+}
+
+int nc_null_poll(int dev) {
+
+ return 1000000;
+}
+
+nw_result nc_null_send(nw_ep ep, nw_tx_header_t header, nw_options options) {
+
+ return NW_FAILURE;
+}
+
+nw_buffer_t nc_null_rpc(nw_ep ep, nw_tx_header_t header, nw_options options) {
+
+ return NW_BUFFER_ERROR;
+}
+
+void nc_null_signal(nw_buffer_t msg) {
+
+}
+
+nw_result nc_open_fail(nw_ep lep, nw_address_1 a1,
+ nw_address_2 a2, nw_ep rep) {
+
+ return NW_FAILURE;
+}
+
+nw_result nc_close_fail(nw_ep ep) {
+
+ return NW_FAILURE;
+}
+
+nw_result nc_accept_fail(nw_ep ep, nw_buffer_t msg, nw_ep_t epp) {
+
+ return NW_FAILURE;
+}
+