|
|
1.1 root 1: #include "../chunix/chsys.h"
2: #include "../chunix/chconf.h"
3: #include "../chaos/chaos.h"
4:
5: /*
6: * Send a STS packet on this connection
7: * if allocation fails it is not sent
8: */
9: sendsts(conn)
10: register struct connection *conn;
11: {
12: register struct packet *pkt;
13:
14: if ((pkt = pkalloc(sizeof(struct sts_data), 1)) != NOPKT) {
15: setpkt(conn, pkt);
16: makests(conn, pkt);
17: sendctl(pkt);
18: }
19: }
20:
21: /*
22: * Send a SNS packet on this connection
23: * if allocation failed nothing is sent
24: */
25: sendsns(conn)
26: register struct connection *conn;
27: {
28: register struct packet *pkt;
29:
30: if ((pkt = pkalloc(0, 1)) != NOPKT) {
31: setpkt(conn, pkt);
32: pkt->pk_op = SNSOP;
33: pkt->pk_lenword = 0;
34: pkt->pk_ackn = conn->cn_racked = conn->cn_rread;
35: sendctl(pkt);
36: }
37: }
38:
39: /*
40: * Send an open in response to a RFC
41: * return NOPKT is allocation fails else, open packet
42: */
43: sendopn(conn)
44: register struct connection *conn;
45: {
46: register struct packet *pkt;
47:
48: if ((pkt = pkalloc(sizeof(struct sts_data), 1)) != NOPKT) {
49: conn->cn_rsts = conn->cn_rwsize >> 1;
50: conn->cn_tlast = 0;
51: pkt->pk_op = OPNOP;
52: pkt->pk_len = sizeof(struct sts_data);
53: pkt->pk_receipt = conn->cn_rlast;
54: pkt->pk_rwsize = conn->cn_rwsize;
55: debug(DCONN,printf("Conn #%x: open sent\n",conn->cn_lidx));
56: (void)ch_write(conn, pkt);
57: }
58: }
59:
60:
61: /*
62: * Following are functions and macros that deal with tranmitters directly
63: *
64: * Macro XMITHEAD (pkt, xcvr) queues pkt on xcvr for transmission, putting
65: * it at the head of the queue for "quick" action. The transmitter is
66: * started if no packet is currently being transmitted.
67: * It is assumed that the pkt is a single one and not a list.
68: * Macro XMITTAIL is similar except that is queues the packet at the tail
69: * of the transmit list, treats the pkt argument as a list, and puts a time
70: * stamp in each packet in the list.
71: * Note that XMITTAIL modifies the variable pkt.
72: */
73: #define XMITHEAD(pkt, axcvr) \
74: { register struct chxcvr *xcvr = axcvr; \
75: pkt->pk_next = xcvr->xc_list; \
76: xcvr->xc_list = pkt; \
77: if (xcvr->xc_tail == NOPKT) { \
78: xcvr->xc_tail = pkt; \
79: if (xcvr->xc_tpkt == NOPKT) \
80: (*xcvr->xc_start)(xcvr); \
81: } \
82: }
83: /*
84: * Sendctl - send a control packet that will not be acknowledged and
85: * will not be retransmitted (this actual packet). Put the
86: * given packet at the head of the transmit queue so it is transmitted
87: * "quickly", i.e. before data packets queued at the tail of the queue.
88: * If anything is wrong (no path, bad subnet) we just throw it
89: * away. Remember, pk_next is assumed to be == NOPKT.
90: */
91: sendctl(pkt)
92: register struct packet *pkt;
93: {
94: register struct chroute *r;
95:
96: debug(DSEND, (printf("Sending: %d ", pkt->pk_op), prpkt(pkt, "ctl"), printf("\n")));
97: if (pkt->pk_dsubnet >= CHNSUBNET ||
98: (r = &Chroutetab[pkt->pk_dsubnet])->rt_type == CHNOPATH)
99: ch_free((char *)pkt);
100: else if (pkt->pk_daddr == Chmyaddr)
101: sendtome(pkt);
102: else {
103: if (r->rt_type == CHFIXED || r->rt_type == CHBRIDGE) {
104: pkt->pk_xdest = r->rt_addr;
105: r = &Chroutetab[r->rt_subnet];
106: } else
107: pkt->pk_xdest = pkt->pk_daddr;
108: XMITHEAD(pkt, r->rt_xcvr);
109: }
110: }
111: /*
112: * Senddata - send a list of controlled packets, all assumed to be to the
113: * same destination. Queue them on the end of the appropriate transmit
114: * queue.
115: * Similar to sendctl, but stuffs time, handles a list, and puts pkts
116: * at the end of the queue instead of at the beginning, and fakes
117: * transmission if it can't really send the packets (as opposed to
118: * throwing the packets away)
119: */
120: senddata(pkt)
121: register struct packet *pkt;
122: {
123: register struct chroute *r;
124:
125: debug(DSEND, (printf("Sending: %d ", pkt->pk_op), prpkt(pkt, "data"), printf("\n")));
126: if (pkt->pk_dsubnet >= CHNSUBNET ||
127: (r = &Chroutetab[pkt->pk_dsubnet])->rt_type == CHNOPATH) {
128: struct packet *npkt;
129:
130: do {
131: npkt = pkt->pk_next;
132: pkt->pk_next = NOPKT;
133: xmitdone(pkt);
134: } while ((pkt = npkt) != NOPKT);
135: } else if (pkt->pk_daddr == Chmyaddr)
136: sendtome(pkt);
137: else {
138: register struct chxcvr *xcvr;
139: register unsigned short dest;
140:
141: if (r->rt_type == CHFIXED || r->rt_type == CHBRIDGE) {
142: dest = r->rt_addr;
143: r = &Chroutetab[r->rt_subnet];
144: } else
145: dest = pkt->pk_daddr;
146: xcvr = r->rt_xcvr;
147: if (xcvr->xc_list == NOPKT)
148: xcvr->xc_list = pkt;
149: else
150: xcvr->xc_tail->pk_next = pkt;
151: for (;;) {
152: pkt->pk_time = Chclock;
153: pkt->pk_xdest = dest;
154: if (pkt->pk_next == NOPKT)
155: break;
156: pkt = pkt->pk_next;
157: }
158: xcvr->xc_tail = pkt;
159: if (xcvr->xc_tpkt == NOPKT)
160: (*xcvr->xc_start)(xcvr);
161: }
162: }
163: /*
164: * Send the given RUT packet out on the given tranceiver, which has the given
165: * cost. If the "copy" flag is true, make a copy of the packet.
166: * Note that if copy is not set, the packet data gets modified.
167: */
168: sendrut(pkt, axcvr, cost, copy)
169: register struct packet *pkt;
170: register struct chxcvr *axcvr;
171: unsigned short cost;
172: int copy;
173: {
174: register struct rut_data *rd;
175: struct rut_data *rdend;
176:
177: if (copy) {
178: struct packet *npkt;
179:
180: if ((npkt = pkalloc((int)pkt->pk_len, 1)) == NOPKT)
181: return;
182: movepkt(pkt, npkt);
183: pkt = npkt;
184: }
185: rdend = (struct rut_data *)(pkt->pk_cdata + pkt->pk_len);
186: for (rd = pkt->pk_rutdata; rd < rdend; rd++)
187: rd->pk_cost += cost;
188: pkt->pk_saddr = axcvr->xc_addr;
189: pkt->pk_xdest = 0;
190: XMITHEAD(pkt, axcvr);
191: }
192: /*
193: * Send the (list of) packet(s) to myself - NOTE THIS CAN BE RECURSIVE!
194: */
195: sendtome(pkt)
196: register struct packet *pkt;
197: {
198: register struct packet *rpkt, *npkt;
199: static struct chxcvr fakexcvr;
200:
201: /*
202: * Static structure is used to economize on stack space.
203: * We are careful to use it very locally so that recursion still
204: * works. Cleaner solutions don't recurse very well.
205: * Basically for each packet in the list, prepare it for
206: * transmission by executing xmitnext,
207: * complete the transmission by calling xmitdone,
208: * then receive the packet on the other side, possibly
209: * causing this routine to recurse (after we're done with the
210: * static structure until next time around the loop)
211: * When this routine is called with a list of data packets, things
212: * can get pretty weird.
213: */
214: while (pkt != NOPKT) {
215: /*
216: * Make the transmit list consist of one packet to send.
217: * Save the rest of the list in npkt.
218: */
219: npkt = pkt->pk_next;
220: pkt->pk_next = NOPKT;
221: fakexcvr.xc_tpkt = NOPKT;
222: fakexcvr.xc_list = fakexcvr.xc_tail = pkt;
223: /*
224: * The xmitnext just dequeues pkt and sets ackn.
225: * It will free the packet if its not worth sending.
226: */
227: (void)xmitnext(&fakexcvr);
228: if (fakexcvr.xc_tpkt) {
229: /*
230: * So it really should be sent.
231: * First make a copy for the receiving side in rpkt.
232: */
233: if ((rpkt = pkalloc((int)pkt->pk_len, 1)) != NOPKT)
234: movepkt(pkt, rpkt);
235: /*
236: * This xmitdone just completes transmission.
237: * Now pkt is out of our hands.
238: */
239: xmitdone(pkt);
240: /*
241: * So transmission is complete. Now receive it.
242: */
243: if (rpkt != NOPKT)
244: rcvpkt(rpkt);
245: }
246: pkt = npkt;
247: }
248: }
249: /*
250: * Indicate that actual transmission of the current packet has been completed.
251: * Called by the device dependent interrupt routine when transmission
252: * of a packet has finished.
253: */
254: xmitdone(pkt)
255: register struct packet *pkt;
256: {
257: register struct connection *conn;
258: register struct packet *npkt;
259:
260: if (pkt->pk_saddr == Chmyaddr && CONTPKT(pkt) &&
261: pkt->pk_stindex < CHNCONNS &&
262: (conn = Chconntab[pkt->pk_stindex]) != NOCONN &&
263: pkt->pk_sidx == conn->cn_lidx &&
264: (conn->cn_state == CSOPEN || conn->cn_state == CSRFCSENT) &&
265: cmp_gt(pkt->pk_pkn, conn->cn_trecvd)) {
266: pkt->pk_time = Chclock;
267: if ((npkt = conn->cn_thead) == NOPKT ||
268: cmp_lt(pkt->pk_pkn, npkt->pk_pkn)) {
269: pkt->pk_next = npkt;
270: conn->cn_thead = pkt;
271: } else {
272: for( ; npkt->pk_next != NOPKT; npkt = npkt->pk_next)
273: if(cmp_lt(pkt->pk_pkn, npkt->pk_next->pk_pkn))
274: break;
275: pkt->pk_next = npkt->pk_next;
276: npkt->pk_next = pkt;
277: }
278: if(pkt->pk_next == NOPKT)
279: conn->cn_ttail = pkt;
280: } else
281: ch_free((char *)pkt);
282: }
283: /*
284: * Return the next packet on which to begin transmission (if none, NOPKT).
285: */
286: struct packet *
287: xmitnext(xcvr)
288: register struct chxcvr *xcvr;
289: {
290: register struct packet *pkt;
291: register struct connection *conn;
292:
293: while ((pkt = xcvr->xc_tpkt = xcvr->xc_list) != NOPKT) {
294: if ((xcvr->xc_list = pkt->pk_next) == NOPKT)
295: xcvr->xc_tail = NOPKT;
296: if (pkt->pk_saddr == Chmyaddr && CONTPKT(pkt))
297: if (pkt->pk_stindex < CHNCONNS &&
298: (conn = Chconntab[pkt->pk_stindex]) != NOCONN &&
299: pkt->pk_sidx == conn->cn_lidx &&
300: (conn->cn_state == CSOPEN || conn->cn_state == CSRFCSENT) &&
301: cmp_gt(pkt->pk_pkn, conn->cn_trecvd))
302: pkt->pk_ackn = conn->cn_racked = conn->cn_rread;
303: else {
304: debug(DPKT,
305: printf("invalid pkt to send: #%x\n",
306: conn->cn_lidx));
307: ch_free((char *)pkt);
308: continue;
309: }
310: xcvr->xc_ttime = Chclock;
311: break;
312: }
313: return (pkt);
314: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.