change iso_pcbconnect so that specifying a null nsap as target
[unix-history] / usr / src / sys / netiso / tp_subr2.c
CommitLineData
3202a7cd
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22******************************************************************/
23
24/*
25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26 */
27/*
28 * ARGO TP
29 *
30 * $Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $
31 * $Source: /usr/argo/sys/netiso/RCS/tp_subr2.c,v $
32 *
33 * Some auxiliary routines:
34 * tp_protocol_error: required by xebec- called when a combo of state,
35 * event, predicate isn't covered for by the transition file.
36 * tp_indicate: gives indications(signals) to the user process
37 * tp_getoptions: initializes variables that are affected by the options
38 * chosen.
39 */
40
41#ifndef lint
42static char *rcsid = "$Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $";
43#endif lint
44
45#include "argoxtwentyfive.h"
46
47/* this def'n is to cause the expansion of this macro in the
48 * routine tp_local_credit :
49 */
50#define LOCAL_CREDIT_EXPAND
51
52#include "param.h"
53#include "mbuf.h"
54#include "socket.h"
55#include "socketvar.h"
56#include "domain.h"
57#include "protosw.h"
58#include "errno.h"
59#include "types.h"
60#include "time.h"
61#include "kernel.h"
62#undef MNULL
a50e2bc0
KS
63#include "argo_debug.h"
64#include "tp_param.h"
65#include "tp_ip.h"
66#include "iso.h"
67#include "iso_errno.h"
68#include "iso_pcb.h"
69#include "tp_timer.h"
70#include "tp_stat.h"
71#include "tp_tpdu.h"
72#include "tp_pcb.h"
73#include "tp_seq.h"
74#include "tp_trace.h"
75#include "tp_user.h"
76#include "cons.h"
3202a7cd
KS
77
78/*
79 * NAME: tp_local_credit()
80 *
81 * CALLED FROM:
82 * tp_emit(), tp_usrreq()
83 *
84 * FUNCTION and ARGUMENTS:
85 * Computes the local credit and stashes it in tpcb->tp_lcredit.
86 * It's a macro in the production system rather than a procdure.
87 *
88 * RETURNS:
89 *
90 * SIDE EFFECTS:
91 *
92 * NOTES:
93 * This doesn't actually get called in a production system -
94 * the macro gets expanded instead in place of calls to this proc.
95 * But for debugging, we call this and that allows us to add
96 * debugging messages easily here.
97 */
98void
99tp_local_credit(tpcb)
100 struct tp_pcb *tpcb;
101{
102 LOCAL_CREDIT(tpcb);
103 IFDEBUG(D_CREDIT)
104 printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n",
105 tpcb->tp_refp - tp_ref,
106 tpcb->tp_lcredit,
107 tpcb->tp_l_tpdusize,
108 tpcb->tp_decbit,
109 tpcb->tp_cong_win
110 );
111 ENDDEBUG
112 IFTRACE(D_CREDIT)
113 tptraceTPCB(TPPTmisc,
114 "lcdt tpdusz \n",
115 tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0);
116 ENDTRACE
117}
118
119/*
120 * NAME: tp_protocol_error()
121 *
122 * CALLED FROM:
123 * tp_driver(), when it doesn't know what to do with
124 * a combo of event, state, predicate
125 *
126 * FUNCTION and ARGUMENTS:
127 * print error mesg
128 *
129 * RETURN VALUE:
130 * EIO - always
131 *
132 * SIDE EFFECTS:
133 *
134 * NOTES:
135 */
136int
137tp_protocol_error(e,tpcb)
138 struct tp_event *e;
139 struct tp_pcb *tpcb;
140{
141 printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n",
142 tpcb, e->ev_number, tpcb->tp_state);
143 IFTRACE(D_DRIVER)
144 tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state",
145 tpcb, e->ev_number, tpcb->tp_state, 0 );
146 ENDTRACE
147 return EIO; /* for lack of anything better */
148}
149
150
151/* Not used at the moment */
152ProtoHook
153tp_drain()
154{
155 return 0;
156}
157
158
159/*
160 * NAME: tp_indicate()
161 *
162 * CALLED FROM:
163 * tp.trans when XPD arrive, when a connection is being disconnected by
164 * the arrival of a DR or ER, and when a connection times out.
165 *
166 * FUNCTION and ARGUMENTS:
167 * (ind) is the type of indication : T_DISCONNECT, T_XPD
168 * (error) is an E* value that will be put in the socket structure
169 * to be passed along to the user later.
170 * Gives a SIGURG to the user process or group indicated by the socket
171 * attached to the tpcb.
172 *
173 * RETURNS: Rien
174 *
175 * SIDE EFFECTS:
176 *
177 * NOTES:
178 */
179void
180tp_indicate(ind, tpcb, error)
181 int ind;
182 u_short error;
183 register struct tp_pcb *tpcb;
184{
185 register struct socket *so = tpcb->tp_sock;
186 IFTRACE(D_INDICATION)
187 tptraceTPCB(TPPTindicate, ind, *(int *)(tpcb->tp_lsuffix),
a50e2bc0 188 *(int *)(tpcb->tp_fsuffix), error,so->so_pgid);
3202a7cd
KS
189 ENDTRACE
190 IFDEBUG(D_INDICATION)
a50e2bc0 191 char *ls, *fs;
3202a7cd
KS
192 ls = tpcb->tp_lsuffix,
193 fs = tpcb->tp_fsuffix,
194
195 printf(
a50e2bc0 196"indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x noind 0x%x ref 0x%x\n",
3202a7cd
KS
197 ind,
198 *ls, *(ls+1), *fs, *(fs+1),
a50e2bc0 199 error, /*so->so_pgrp,*/
3202a7cd
KS
200 tpcb->tp_no_disc_indications,
201 tpcb->tp_lref);
202 ENDDEBUG
203
204 so->so_error = error;
205
206 if (ind == T_DISCONNECT) {
207 if ( tpcb->tp_no_disc_indications )
208 return;
209 }
210 IFTRACE(D_INDICATION)
211 tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0);
212 ENDTRACE
213 sohasoutofband(so);
214}
215
216/*
217 * NAME : tp_getoptions()
218 *
219 * CALLED FROM:
220 * tp.trans whenever we go into OPEN state
221 *
222 * FUNCTION and ARGUMENTS:
223 * sets the proper flags and values in the tpcb, to control
224 * the appropriate actions for the given class, options,
225 * sequence space, etc, etc.
226 *
227 * RETURNS: Nada
228 *
229 * SIDE EFFECTS:
230 *
231 * NOTES:
232 */
233void
234tp_getoptions(tpcb)
235struct tp_pcb *tpcb;
236{
237 tpcb->tp_seqmask =
238 tpcb->tp_xtd_format ? TP_XTD_FMT_MASK : TP_NML_FMT_MASK ;
239 tpcb->tp_seqbit =
240 tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ;
241 tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
242 tpcb->tp_dt_ticks =
243 MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2));
244
245}
246
247/*
248 * NAME: tp_recycle_tsuffix()
249 *
250 * CALLED FROM:
251 * Called when a ref is frozen.
252 *
253 * FUNCTION and ARGUMENTS:
254 * allows the suffix to be reused.
255 *
256 * RETURNS: zilch
257 *
258 * SIDE EFFECTS:
259 *
260 * NOTES:
261 */
262void
263tp_recycle_tsuffix(tpcb)
264 struct tp_pcb *tpcb;
265{
a50e2bc0
KS
266 bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix));
267 bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix));
3202a7cd
KS
268 tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0;
269
270 (tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb);
271}
272
273/*
274 * NAME: tp_quench()
275 *
276 * CALLED FROM:
277 * tp{af}_quench() when ICMP source quench or similar thing arrives.
278 *
279 * FUNCTION and ARGUMENTS:
280 * Drop the congestion window back to 1.
281 * Congestion window scheme:
282 * Initial value is 1. ("slow start" as Nagle, et. al. call it)
283 * For each good ack that arrives, the congestion window is increased
284 * by 1 (up to max size of logical infinity, which is to say,
285 * it doesn't wrap around).
286 * Source quench causes it to drop back to 1.
287 * tp_send() uses the smaller of (regular window, congestion window).
288 * One retransmission strategy option is to have any retransmission
289 * cause reset the congestion window back to 1.
290 *
291 * (cmd) is either PRC_QUENCH: source quench, or
292 * PRC_QUENCH2: dest. quench (dec bit)
293 *
294 * RETURNS:
295 *
296 * SIDE EFFECTS:
297 *
298 * NOTES:
299 */
300void
301tp_quench( tpcb, cmd )
302 struct tp_pcb *tpcb;
303 int cmd;
304{
305 IFDEBUG(D_QUENCH)
306 printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
307 tpcb, tpcb->tp_lref, *(int *)(tpcb->tp_lsuffix));
308 printf("cong_win 0x%x decbit 0x%x \n",
309 tpcb->tp_cong_win, tpcb->tp_decbit);
310 ENDDEBUG
311 switch(cmd) {
312 case PRC_QUENCH:
313 tpcb->tp_cong_win = 1;
314 IncStat(ts_quench);
315 break;
316 case PRC_QUENCH2:
317 tpcb->tp_cong_win = 1; /* might as well quench source also */
318 tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT;
319 IncStat(ts_rcvdecbit);
320 break;
321 }
322}
323
324
325/*
326 * NAME: tp_netcmd()
327 *
328 * CALLED FROM:
329 *
330 * FUNCTION and ARGUMENTS:
331 *
332 * RETURNS:
333 *
334 * SIDE EFFECTS:
335 *
336 * NOTES:
337 */
338tp_netcmd( tpcb, cmd )
339 struct tp_pcb *tpcb;
340 int cmd;
341{
342#if NARGOXTWENTYFIVE > 0
343 switch (cmd) {
344
345 case CONN_CLOSE:
346 case CONN_REFUSE:
347 cons_netcmd( cmd, tpcb->tp_npcb, 0, tpcb->tp_class == TP_CLASS_4);
348 /* TODO: can this last param be replaced by
349 * tpcb->tp_netserv != ISO_CONS?)
350 */
351 break;
352
353 default:
354 printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
355 break;
356 }
357#else NARGOXTWENTYFIVE
358 printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
359#endif NARGOXTWENTYFIVE > 0
360}
361/*
362 * CALLED FROM:
363 * tp_ctloutput() and tp_emit()
364 * FUNCTION and ARGUMENTS:
365 * Convert a class mask to the highest numeric value it represents.
366 */
367
368int
369tp_mask_to_num(x)
370 u_char x;
371{
372 register int j;
373
374 for(j = 4; j>=0 ;j--) {
375 if(x & (1<<j))
376 break;
377 }
378 ASSERT( (j == 4) || (j == 0) ); /* for now */
379 if( (j != 4) && (j != 0) ) {
380 printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n",
381 x, j);
382 }
383 IFTRACE(D_TPINPUT)
384 tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0);
385 ENDTRACE
386 IFDEBUG(D_TPINPUT)
387 printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j);
388 ENDDEBUG
389 return j;
390}
391
392static
393copyQOSparms(src, dst)
394 struct tp_conn_param *src, *dst;
395{
396 /* copy all but the bits stuff at the end */
397#define COPYSIZE (12 * sizeof(short))
398
a50e2bc0 399 bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE);
3202a7cd
KS
400 dst->p_tpdusize = src->p_tpdusize;
401 dst->p_ack_strat = src->p_ack_strat;
402 dst->p_rx_strat = src->p_rx_strat;
403#undef COPYSIZE
404}
405
406/*
407 * CALLED FROM:
408 * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR
409 *
410 * FUNCTION and ARGUMENTS:
411 * route directly to x.25 if the address is type 37 - GROT.
412 * furthermore, let TP0 handle only type-37 addresses
413 *
414 * Since this assumes that its address argument is in a mbuf, the
415 * parameter was changed to reflect this assumtion. This also
416 * implies that an mbuf must be allocated when this is
417 * called from tp_input
418 *
419 * RETURNS:
420 * errno value :
421 * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic)
422 * ECONNREFUSED if trying to run TP0 with non-type 37 address
423 * possibly other E* returned from cons_netcmd()
424 * NOTE:
425 * Would like to eliminate as much of this as possible --
426 * only one set of defaults (let the user set the parms according
427 * to parameters provided in the directory service).
428 * Left here for now 'cause we don't yet have a clean way to handle
429 * it on the passive end.
430 */
431int
432tp_route_to( m, tpcb, channel)
433 struct mbuf *m;
434 register struct tp_pcb *tpcb;
435 u_int channel;
436{
437 register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */
438 extern struct tp_conn_param tp_conn_param[];
439 int error = 0;
440 int vc_to_kill = 0; /* kludge */
441
442 siso = mtod(m, struct sockaddr_iso *);
443 IFTRACE(D_CONN)
444 tptraceTPCB(TPPTmisc,
445 "route_to: so afi netservice class",
a50e2bc0 446 tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice,
3202a7cd
KS
447 tpcb->tp_class);
448 ENDTRACE
449 IFDEBUG(D_CONN)
450 printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n",
451 m, channel, tpcb, tpcb->tp_netservice);
452 printf("m->mlen x%x, m->m_data:\n", m->m_len);
453 dump_buf(mtod(m, caddr_t), m->m_len);
454 ENDDEBUG
455 if( siso->siso_family != tpcb->tp_domain ) {
456 error = EAFNOSUPPORT;
457 goto done;
458 }
a50e2bc0
KS
459 IFDEBUG(D_CONN)
460 printf("tp_route_to calling nlp_pcbconn, netserv %d\n",
461 tpcb->tp_netservice);
462 ENDDEBUG
463 error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_sock->so_pcb, m);
464 if( error )
465 goto done;
466
3202a7cd
KS
467 {
468 register int save_netservice = tpcb->tp_netservice;
469
470 switch(tpcb->tp_netservice) {
471 case ISO_COSNS:
472 case ISO_CLNS:
473 /* This is a kludge but seems necessary so the passive end
474 * can get long enough timers. sigh.
a50e2bc0 475 if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET )
3202a7cd 476 */
a50e2bc0 477 if( siso->siso_addr.isoa_genaddr[2] == (char)IDI_OSINET ) {
3202a7cd
KS
478 if( tpcb->tp_dont_change_params == 0) {
479 copyQOSparms( &tp_conn_param[ISO_COSNS],
480 &tpcb->_tp_param);
481 }
482 tpcb->tp_flags |= TPF_NLQOS_PDN;
483 }
484 /* drop through to IN_CLNS*/
485 case IN_CLNS:
a50e2bc0
KS
486 if (iso_localifa(siso))
487 tpcb->tp_flags |= TPF_PEER_ON_SAMENET;
3202a7cd
KS
488 if( (tpcb->tp_class & TP_CLASS_4)==0 ) {
489 error = EPROTOTYPE;
490 break;
491 }
492 tpcb->tp_class = TP_CLASS_4; /* IGNORE dont_change_parms */
493 break;
494
495 case ISO_CONS:
496#if NARGOXTWENTYFIVE > 0
497 tpcb->tp_flags |= TPF_NLQOS_PDN;
498 if( tpcb->tp_dont_change_params == 0 ) {
499 copyQOSparms( &tp_conn_param[ISO_CONS],
500 &tpcb->_tp_param);
501 }
502 /*
503 * for use over x.25 really need a small receive window,
504 * need to start slowly, need small max negotiable tpdu size,
505 * and need to use the congestion window to the max
506 * IGNORES tp_dont_change_params for these!
507 */
508 if( tpcb->tp_sock->so_snd.sb_hiwat > 512 ) {
509 (void) soreserve(tpcb->tp_sock, 512, 512 );/* GAG */
510 }
511 tpcb->tp_rx_strat = TPRX_USE_CW;
512
513 if( (tpcb->tp_nlproto != &nl_protosw[ISO_CONS]) ) {
514 /* if the listener was restricting us to clns,
515 * ( we never get here if the listener isn't af_iso )
516 * refuse the connection :
517 * but we don't have a way to restrict thus - it's
518 * utterly permissive.
519 if(channel) {
520 (void) cons_netcmd(CONN_REFUSE, tpcb->tp_npcb,
521 channel, tpcb->tp_class == TP_CLASS_4);
522 error = EPFNOSUPPORT;
523 goto done;
524 }
525 */
526 IFDEBUG(D_CONN)
527 printf(
528 "tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n",
529 tpcb->tp_nlproto , &nl_protosw[ISO_CONS]);
530 ENDDEBUG
531 tpcb->tp_nlproto = &nl_protosw[ISO_CONS];
532 }
533 /* Now we've got the right nl_protosw.
534 * If we already have a channel (we were called from tp_input())
535 * tell cons that we'll hang onto this channel.
536 * If we don't already have one (we were called from usrreq())
537 * -and if it's TP0 open a net connection and wait for it to finish.
538 */
539 if( channel ) {
540 error = cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb,
541 channel, tpcb->tp_class == TP_CLASS_4);
542 vc_to_kill ++;
543 } else if( tpcb->tp_class != TP_CLASS_4 /* class 4 only */) {
544 /* better open vc if any possibility of ending up
545 * in non-multiplexing class
546 */
547 error = cons_openvc(tpcb->tp_npcb, siso, tpcb->tp_sock);
548 vc_to_kill ++;
549 }
550 /* class 4 doesn't need to open a vc now - may use one already
551 * opened or may open one only when it sends a pkt.
552 */
553#else NARGOXTWENTYFIVE > 0
554 error = ECONNREFUSED;
555#endif NARGOXTWENTYFIVE > 0
556 break;
557 default:
558 error = EPROTOTYPE;
559 }
560
561 ASSERT( save_netservice == tpcb->tp_netservice);
562 }
3202a7cd
KS
563 if( error && vc_to_kill ) {
564 tp_netcmd( tpcb, CONN_CLOSE);
565 goto done;
566 }
3202a7cd
KS
567 { /* start with the global rtt, rtv stats */
568 register int i =
569 (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN);
570
571 tpcb->tp_rtt = tp_stat.ts_rtt[i];
572 tpcb->tp_rtv = tp_stat.ts_rtv[i];
573 }
574done:
575 IFDEBUG(D_CONN)
576 printf("tp_route_to returns 0x%x\n", error);
577 ENDDEBUG
578 IFTRACE(D_CONN)
579 tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error,
580 tpcb->tp_netservice, tpcb->tp_class, 0);
581 ENDTRACE
582 return error;
583}
584
585#ifdef TP_PERF_MEAS
586/*
587 * CALLED FROM:
588 * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on
589 * and tp_newsocket() when a new connection is made from
590 * a listening socket with tp_perf_on == true.
591 * FUNCTION and ARGUMENTS:
592 * (tpcb) is the usual; this procedure gets a clear cluster mbuf for
593 * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it.
594 * RETURN VALUE:
595 * ENOBUFS if it cannot get a cluster mbuf.
596 */
597
598int
599tp_setup_perf(tpcb)
600 register struct tp_pcb *tpcb;
601{
602 register struct mbuf *q;
603
a50e2bc0
KS
604 if( tpcb->tp_p_meas == 0 ) {
605 MGET(q, M_WAITOK, MT_PCB);
3202a7cd
KS
606 if (q == 0)
607 return ENOBUFS;
a50e2bc0
KS
608 MCLGET(q, M_WAITOK);
609 if ((q->m_flags & M_EXT) == 0) {
610 (void) m_free(q);
3202a7cd 611 return ENOBUFS;
3202a7cd 612 }
a50e2bc0
KS
613 q->m_len = sizeof (struct tp_pmeas);
614 tpcb->tp_p_mbuf = q;
615 tpcb->tp_p_meas = mtod(q, struct tp_pmeas *);
616 bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) );
617 IFDEBUG(D_PERF_MEAS)
618 printf(
619 "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n",
620 tpcb, tpcb->tp_sock, tpcb->tp_lref,
621 tpcb->tp_p_meas, tpcb->tp_perf_on);
622 ENDDEBUG
623 tpcb->tp_perf_on = 1;
3202a7cd
KS
624 }
625 return 0;
626}
627#endif TP_PERF_MEAS
628
629#ifdef ARGO_DEBUG
630dump_addr (addr)
631 register struct sockaddr *addr;
632{
633 switch( addr->sa_family ) {
634 case AF_INET:
a50e2bc0 635 dump_inaddr((struct sockaddr_in *)addr);
3202a7cd 636 break;
a50e2bc0 637#ifdef ISO
3202a7cd 638 case AF_ISO:
a50e2bc0 639 dump_isoaddr((struct sockaddr_iso *)addr);
3202a7cd 640 break;
a50e2bc0 641#endif ISO
3202a7cd
KS
642 default:
643 printf("BAD AF: 0x%x\n", addr->sa_family);
644 break;
645 }
646}
647
a50e2bc0
KS
648#define MAX_COLUMNS 8
649/*
650 * Dump the buffer to the screen in a readable format. Format is:
651 *
652 * hex/dec where hex is the hex format, dec is the decimal format.
653 * columns of hex/dec numbers will be printed, followed by the
654 * character representations (if printable).
655 */
656Dump_buf(buf, len)
657caddr_t buf;
658int len;
659{
660 int i,j;
661
662 printf("Dump buf 0x%x len 0x%x\n", buf, len);
663 for (i = 0; i < len; i += MAX_COLUMNS) {
664 printf("+%d:\t", i);
665 for (j = 0; j < MAX_COLUMNS; j++) {
666 if (i + j < len) {
667 printf("%x/%d\t", buf[i+j]&0xff, buf[i+j]);
668 } else {
669 printf(" ");
670 }
671 }
672
673 for (j = 0; j < MAX_COLUMNS; j++) {
674 if (i + j < len) {
675 if (((buf[i+j]) > 31) && ((buf[i+j]) < 128))
676 printf("%c", buf[i+j]&0xff);
677 else
678 printf(".");
679 }
680 }
681 printf("\n");
682 }
683}
684
685
3202a7cd
KS
686#endif ARGO_DEBUG
687