V8/usr/sys/chaosld/chsend.c

/*
 *             C H  S E N D
 *
 * Chaosnet line discipline - routines to deal with sending out packets.
 *
 *
 * (c) Copyright 1985  Nirvonics, Inc.
 *
 * Written by Kurt Gollhardt
 * Last update Thu Feb 28 14:42:57 1985
 *
 * This software is the property of Nirvonics, Inc.
 * All rights reserved.
 *
 */

#include "ch.h"
#if NCH > 0
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/stream.h"
#include "../h/conf.h"
#include "../chaosld/types.h"
#include "../chaosld/constants.h"
#include "../chaosld/globals.h"
#include "../chaosld/chrouteld.h"

/*
 * Send a STS packet on this connection
 *     if allocation fails it is not sent
 */
sendsts(conn)
register struct connection *conn;
{
     register struct packet *pkt;

     if ((pkt = new_packet()) != NOPKT) {
          setconn(conn, pkt);
          setsts(conn, pkt);
          sendctl(pkt);
     }
}

/*
 * Send a SNS packet on this connection
 *     if allocation failed nothing is sent
 */
sendsns(conn)
     register struct connection    *conn;
{
     register struct packet   *pkt;

     if ((pkt = new_packet()) != NOPKT) {
          setconn(conn, pkt);
          pkt->pk_op = SNSOP;
          setack(conn, pkt);
          sendctl(pkt);
     }
}

/*
 * Send an open in response to an RFC
 */

sendopn(conn)
     register struct connection    *conn;
{
     register struct packet   *pkt;

     if ((pkt = new_packet()) != NOPKT) {
          conn->cn_rsts = conn->cn_rwsize >> 1;
	  conn->cn_tlast = 0;
	  setconn(conn, pkt);
	  setsts(conn, pkt);
	  pkt->pk_op = OPNOP;
          chld_write(conn, pkt);
     }
}

/*
 * Sendctl - send a control packet that will not be acknowledged and
 *     will not be retransmitted (this actual packet).
 *     If anything is wrong (no path, bad subnet) we just throw it
 *     away. Remember, next is assumed to be == NOPKT.
 */
sendctl(pkt)
register struct packet *pkt;
{
     register struct chroute *r;

     debug(DSEND, (printf("Sending: %d ", pkt->pk_op), prpkt(pkt, "ctl"), printf("\n")));
     ch_busy++;
     put_packet(WR(ChaosQ), pkt);
     --ch_busy;
}

/*
 * Senddata - send a list of controlled packets.
 *     Similar to sendctl, but stuffs time, handles a list, and marks
 *     the packets as transmitted.
 */
senddata(pkt)
register struct packet *pkt;
{
     register struct packet   *nextpk;

     debug(DSEND, (printf("Sending: %d ", pkt->pk_op), prpkt(pkt, "data"), printf("\n")));
     ch_busy++;
     do {
          pkt->time = Chclock;
          nextpk = pkt->next;
          copy_packet(WR(ChaosQ), pkt);
          xmitdone(pkt);
     } while ((pkt = nextpk) != NOPKT);
     --ch_busy;
}

/*
 * Send the given RUT packet out on the given tranceiver, which has the given
 * cost.  If the "copy" flag is true, make a copy of the packet.
 * Note that if copy is not set, the packet data gets modified.
 */
sendrut(pkt, ifp, cost, copy)
register struct packet *pkt;
register struct chif *ifp;
unsigned short cost;
int copy;
{
     register struct rut_data *rd;
     struct rut_data *rdend;

     pkt->pk_saddr = ifp->my_addr;
     pkt->pk_daddr.ch_subnet = ifp->my_addr.ch_subnet;

     rdend = (struct rut_data *)(pkt->data->rptr + pkt->pk_len);
     for (rd = (struct rut_data *)pkt->data->rptr; rd < rdend; rd++)
          rd->rd_cost += cost;

     ch_busy++;
     if (copy) {
	  copy_packet(WR(ChaosQ), pkt);
	  for (rd = (struct rut_data *)pkt->data->rptr; rd < rdend; rd++)
	       rd->rd_cost -= cost;
     } else
	  put_packet(WR(ChaosQ), pkt);
     --ch_busy;
}

/*
 * Send a LOS in response to the given packet.
 * Don't bother if the packet is itself a LOS or a CLS since the other
 * end doesn't care anyway and would only return it again.
 * Append the host name to the error message.
 */
sendlos(pkt, str, msglen)
     register struct packet   *pkt;
     char      *str;
     int       msglen;
{
     if (pkt->pk_op == LOSOP || pkt->pk_op == CLSOP)
          free_packet(pkt);
     else {
          register struct block    *bp;
          register char  *cp;
          register int   namelen;

	  for (namelen = 0, cp = Chmyname; *cp++;)
	       ++namelen;

          free_pkdata(pkt);
          append_packet(pkt, str, msglen);
          append_packet(pkt, " (from ", 7);
          append_packet(pkt, Chmyname, namelen);
          append_packet(pkt, ")", 1);

          pkt->pk_op = LOSOP;
          reflect(pkt);
     }
}

/*
 * Send a control packet back to its source
 */
reflect(pkt)
     register struct packet   *pkt;
{
     register short temp;

     temp = pkt->pk_sidx.ci_idx;
     pkt->pk_sidx = pkt->pk_didx;
     pkt->pk_didx.ci_idx = temp;
     temp = pkt->pk_saddr.ch_addr;
     pkt->pk_saddr = pkt->pk_daddr;
     pkt->pk_daddr.ch_addr = temp;
     sendctl(pkt);
}

/*
 * Indicate that actual transmission of the current packet has been completed.
 * Note that this merely means that we've sent it on to the routing line
 * discipline, and there's no guarantee that it's really gone anywhere.
 *
 * If this is a controlled packet and the connection is open, put the packet
 * on the queue of transmitted packets awaiting acknowledgements, otherwise
 * throw away the packet.
 */
xmitdone(pkt)
     register struct packet   *pkt;
{
     register struct connection *conn;
     register struct packet   *npkt;

     ch_busy++;
     if (CONTROLLED(pkt) && pkt->pk_sidx.ci_tidx < NCH &&
               (conn = Chconn[pkt->pk_sidx.ci_tidx]) != NOCONN &&
               pkt->pk_sidx.ci_idx == conn->cn_lidx.ci_idx &&
               (conn->cn_state == CSOPEN || conn->cn_state == CSRFCSENT) &&
               cmp_gt(pkt->pk_pkn, conn->cn_trecvd)) {
          pkt->time = Chclock;
          if ((npkt = conn->cn_thead) == NOPKT || 
                    cmp_lt(pkt->pk_pkn, npkt->pk_pkn)) {
               pkt->next = npkt;
               conn->cn_thead = pkt;
          } else {
               for(; npkt->next != NOPKT; npkt = npkt->next)
                    if(cmp_lt(pkt->pk_pkn, npkt->next->pk_pkn))
                         break;
               pkt->next = npkt->next;
               npkt->next = pkt;
          }
          if(pkt->next == NOPKT)
               conn->cn_ttail = pkt;
     } else
          free_packet(pkt);
     --ch_busy;
}

#endif