141709Ssklower /* 241709Ssklower * Copyright (c) University of British Columbia, 1984 341709Ssklower * Copyright (c) 1990 The Regents of the University of California. 441709Ssklower * All rights reserved. 541709Ssklower * 641709Ssklower * This code is derived from software contributed to Berkeley by 741709Ssklower * the Laboratory for Computation Vision and the Computer Science Department 841709Ssklower * of the University of British Columbia. 941709Ssklower * 1041709Ssklower * %sccs.include.redist.c% 1141709Ssklower * 12*49018Ssklower * @(#)pk_subr.c 7.12 (Berkeley) 05/03/91 1341709Ssklower */ 1441593Ssklower 1542140Ssklower #include "param.h" 1642140Ssklower #include "systm.h" 1742140Ssklower #include "mbuf.h" 1842140Ssklower #include "socket.h" 1942140Ssklower #include "protosw.h" 2042140Ssklower #include "socketvar.h" 2142140Ssklower #include "errno.h" 2242140Ssklower #include "time.h" 2342140Ssklower #include "kernel.h" 2441593Ssklower 2542277Ssklower #include "../net/if.h" 2642277Ssklower 2742140Ssklower #include "x25.h" 2842140Ssklower #include "pk.h" 2942140Ssklower #include "pk_var.h" 3042140Ssklower #include "x25err.h" 3141593Ssklower 3241593Ssklower int pk_sendspace = 1024 * 2 + 8; 3341593Ssklower int pk_recvspace = 1024 * 2 + 8; 3441593Ssklower 3547271Ssklower struct pklcd_q pklcd_q = {&pklcd_q, &pklcd_q}; 3647271Ssklower 3741593Ssklower /* 3841593Ssklower * Attach X.25 protocol to socket, allocate logical channel descripter 3941593Ssklower * and buffer space, and enter LISTEN state if we are to accept 4041593Ssklower * IN-COMMING CALL packets. 4141593Ssklower * 4241593Ssklower */ 4341593Ssklower 4442277Ssklower struct pklcd * 4541593Ssklower pk_attach (so) 4641593Ssklower struct socket *so; 4741593Ssklower { 4841593Ssklower register struct pklcd *lcp; 4942277Ssklower register int error = ENOBUFS; 50*49018Ssklower int pk_output(); 5141593Ssklower 5247271Ssklower MALLOC(lcp, struct pklcd *, sizeof (*lcp), M_PCB, M_NOWAIT); 5342277Ssklower if (lcp) { 5447271Ssklower bzero ((caddr_t)lcp, sizeof (*lcp)); 5547271Ssklower insque (&lcp -> lcd_q, &pklcd_q); 5642277Ssklower if (so) { 5742277Ssklower error = soreserve (so, pk_sendspace, pk_recvspace); 5842277Ssklower lcp -> lcd_so = so; 5942277Ssklower if (so -> so_options & SO_ACCEPTCONN) 6042277Ssklower lcp -> lcd_state = LISTEN; 6142277Ssklower else 6242277Ssklower lcp -> lcd_state = READY; 6343361Ssklower } else 6445165Ssklower sbreserve (&lcp -> lcd_sb, pk_sendspace); 6542277Ssklower } 6642277Ssklower if (so) { 6742277Ssklower so -> so_pcb = (caddr_t) lcp; 6842277Ssklower so -> so_error = error; 6942277Ssklower } 70*49018Ssklower lcp -> lcd_send = pk_output; 7142277Ssklower return (lcp); 7241593Ssklower } 7341593Ssklower 7441593Ssklower /* 7541593Ssklower * Disconnect X.25 protocol from socket. 7641593Ssklower */ 7741593Ssklower 7841593Ssklower pk_disconnect (lcp) 7941593Ssklower register struct pklcd *lcp; 8041593Ssklower { 8141593Ssklower register struct socket *so = lcp -> lcd_so; 8241593Ssklower register struct pklcd *l, *p; 8341593Ssklower 8441593Ssklower switch (lcp -> lcd_state) { 8541593Ssklower case LISTEN: 8641593Ssklower for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen); 8741593Ssklower if (p == 0) { 8841593Ssklower if (l != 0) 8941593Ssklower pk_listenhead = l -> lcd_listen; 9041593Ssklower } 9141593Ssklower else 9241593Ssklower if (l != 0) 9341593Ssklower p -> lcd_listen = l -> lcd_listen; 9441593Ssklower pk_close (lcp); 9541593Ssklower break; 9641593Ssklower 9741593Ssklower case READY: 9841593Ssklower pk_acct (lcp); 9941593Ssklower pk_close (lcp); 10041593Ssklower break; 10141593Ssklower 10241593Ssklower case SENT_CLEAR: 10341593Ssklower case RECEIVED_CLEAR: 10441593Ssklower break; 10541593Ssklower 10641593Ssklower default: 10741593Ssklower pk_acct (lcp); 10842140Ssklower if (so) { 10942140Ssklower soisdisconnecting (so); 11042140Ssklower sbflush (&so -> so_rcv); 11142140Ssklower } 11245895Ssklower pk_clear (lcp, 241, 0); /* Normal Disconnect */ 11341593Ssklower 11441593Ssklower } 11541593Ssklower } 11641593Ssklower 11741593Ssklower /* 11841593Ssklower * Close an X.25 Logical Channel. Discard all space held by the 11941593Ssklower * connection and internal descriptors. Wake up any sleepers. 12041593Ssklower */ 12141593Ssklower 12241593Ssklower pk_close (lcp) 12341593Ssklower struct pklcd *lcp; 12441593Ssklower { 12541593Ssklower register struct socket *so = lcp -> lcd_so; 12641593Ssklower 12741593Ssklower pk_freelcd (lcp); 12841593Ssklower 12941593Ssklower if (so == NULL) 13041593Ssklower return; 13141593Ssklower 13241593Ssklower so -> so_pcb = 0; 13341593Ssklower soisdisconnected (so); 13445895Ssklower /* sofree (so); /* gak!!! you can't do that here */ 13541593Ssklower } 13641593Ssklower 13741593Ssklower /* 13841593Ssklower * Create a template to be used to send X.25 packets on a logical 13941593Ssklower * channel. It allocates an mbuf and fills in a skeletal packet 14041593Ssklower * depending on its type. This packet is passed to pk_output where 14141593Ssklower * the remainer of the packet is filled in. 14241593Ssklower */ 14341593Ssklower 14445895Ssklower struct mbuf * 14541593Ssklower pk_template (lcn, type) 14641593Ssklower int lcn, type; 14741593Ssklower { 14841593Ssklower register struct mbuf *m; 14941593Ssklower register struct x25_packet *xp; 15041593Ssklower 15145297Ssklower MGETHDR (m, M_DONTWAIT, MT_HEADER); 15241593Ssklower if (m == 0) 15341593Ssklower panic ("pk_template"); 15441593Ssklower m -> m_act = 0; 15541593Ssklower 15641593Ssklower /* 15741593Ssklower * Efficiency hack: leave a four byte gap at the beginning 15841593Ssklower * of the packet level header with the hope that this will 15941593Ssklower * be enough room for the link level to insert its header. 16041593Ssklower */ 16145297Ssklower m -> m_data += max_linkhdr; 16241593Ssklower m -> m_len = PKHEADERLN; 16341593Ssklower 16441593Ssklower xp = mtod (m, struct x25_packet *); 16541593Ssklower *(long *)xp = 0; /* ugly, but fast */ 16641593Ssklower /* xp -> q_bit = 0;*/ 16741593Ssklower xp -> fmt_identifier = 1; 16841593Ssklower /* xp -> lc_group_number = 0;*/ 16941593Ssklower 17045574Ssklower SET_LCN(xp, lcn); 17141593Ssklower xp -> packet_type = type; 17241593Ssklower 17345895Ssklower return (m); 17441593Ssklower } 17541593Ssklower 17641593Ssklower /* 17741593Ssklower * This routine restarts all the virtual circuits. Actually, 17841593Ssklower * the virtual circuits are not "restarted" as such. Instead, 17941593Ssklower * any active switched circuit is simply returned to READY 18041593Ssklower * state. 18141593Ssklower */ 18241593Ssklower 18341593Ssklower pk_restart (pkp, restart_cause) 18441593Ssklower register struct pkcb *pkp; 18541593Ssklower int restart_cause; 18641593Ssklower { 18745895Ssklower register struct mbuf *m; 18841593Ssklower register struct pklcd *lcp; 18941593Ssklower register int i; 19041593Ssklower 19141593Ssklower /* Restart all logical channels. */ 19245297Ssklower if (pkp -> pk_chan == 0) 19342140Ssklower return; 19445297Ssklower for (i = 1; i <= pkp -> pk_maxlcn; ++i) 19545297Ssklower if ((lcp = pkp -> pk_chan[i]) != NULL) { 19645895Ssklower if (lcp -> lcd_so) { 19745297Ssklower lcp -> lcd_so -> so_error = ENETRESET; 19845895Ssklower pk_close (lcp); 19945895Ssklower } else { 20045895Ssklower pk_flush (lcp); 20145895Ssklower lcp -> lcd_state = READY; 20245895Ssklower if (lcp -> lcd_upper) 20347271Ssklower lcp -> lcd_upper (lcp, 0); 20445895Ssklower } 20541593Ssklower } 20641593Ssklower 20741593Ssklower if (restart_cause < 0) 20841593Ssklower return; 20941593Ssklower 21045297Ssklower pkp -> pk_state = DTE_SENT_RESTART; 21145297Ssklower lcp = pkp -> pk_chan[0]; 21245895Ssklower m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART); 21345895Ssklower m -> m_len += 2; 21447271Ssklower mtod (m, struct x25_packet *) -> packet_data = 0; /* DTE only */ 21547271Ssklower mtod (m, octet *)[4] = restart_cause; 21641593Ssklower pk_output (lcp); 21741593Ssklower } 21841593Ssklower 21941593Ssklower 22041593Ssklower /* 22141593Ssklower * This procedure frees up the Logical Channel Descripter. 22241593Ssklower */ 22341593Ssklower 22441593Ssklower pk_freelcd (lcp) 22541593Ssklower register struct pklcd *lcp; 22641593Ssklower { 22741593Ssklower if (lcp == NULL) 22841593Ssklower return; 22941593Ssklower 23041593Ssklower if (lcp -> lcd_lcn > 0) 23141593Ssklower lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL; 23241593Ssklower 23347271Ssklower pk_flush (lcp); 23447271Ssklower remque (&lcp -> lcd_q); 23547271Ssklower free ((caddr_t)lcp, M_PCB); 23641593Ssklower } 23741593Ssklower 23841593Ssklower 23941593Ssklower /* 24041593Ssklower * Bind a address and protocol value to a socket. The important 24141593Ssklower * part is the protocol value - the first four characters of the 24241593Ssklower * Call User Data field. 24341593Ssklower */ 24441593Ssklower 24541593Ssklower pk_bind (lcp, nam) 24641593Ssklower struct pklcd *lcp; 24741593Ssklower struct mbuf *nam; 24841593Ssklower { 24941593Ssklower register struct pkcb *pkp; 25041593Ssklower register struct pklcd *pp; 25142277Ssklower register struct sockaddr_x25 *sa; 25241593Ssklower 25341593Ssklower if (nam == NULL) 25441593Ssklower return (EADDRNOTAVAIL); 25541593Ssklower if (lcp -> lcd_ceaddr) /* XXX */ 25641593Ssklower return (EADDRINUSE); 25745895Ssklower if (pk_checksockaddr (nam)) 25841593Ssklower return (EINVAL); 25941593Ssklower sa = mtod (nam, struct sockaddr_x25 *); 26041593Ssklower 26141593Ssklower /* 26241593Ssklower * If the user wishes to accept calls only from a particular 26341593Ssklower * net (net != 0), make sure the net is known 26441593Ssklower */ 26541593Ssklower 26641593Ssklower if (sa -> x25_net) 26741593Ssklower for (pkp = pkcbhead; ; pkp = pkp -> pk_next) { 26841593Ssklower if (pkp == 0) 26941593Ssklower return (ENETUNREACH); 27045165Ssklower if (pkp -> pk_xcp -> xc_addr.x25_net == sa -> x25_net) 27141593Ssklower break; 27241593Ssklower } 27341593Ssklower 27445895Ssklower /* 27545895Ssklower * For ISO's sake permit default listeners, but only one such . . . 27645895Ssklower */ 27745895Ssklower for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) { 27845895Ssklower register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr; 27945895Ssklower if ((sa2 -> x25_udlen == sa -> x25_udlen) && 28045895Ssklower (sa2 -> x25_udlen == 0 || 28145895Ssklower (bcmp (sa2 -> x25_udata, sa -> x25_udata, 28245895Ssklower min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0))) 28345895Ssklower return (EADDRINUSE); 28445895Ssklower } 28542277Ssklower lcp -> lcd_laddr = *sa; 28642277Ssklower lcp -> lcd_ceaddr = &lcp -> lcd_laddr; 28741593Ssklower return (0); 28841593Ssklower } 28941593Ssklower 29041593Ssklower /* 29145895Ssklower * Include a bound control block in the list of listeners. 29245895Ssklower */ 29345895Ssklower pk_listen (lcp) 29445895Ssklower register struct pklcd *lcp; 29545895Ssklower { 29645895Ssklower register struct pklcd **pp; 29745895Ssklower 29845895Ssklower if (lcp -> lcd_ceaddr == 0) 29945895Ssklower return (EDESTADDRREQ); 30045895Ssklower 30145895Ssklower lcp -> lcd_state = LISTEN; 30245895Ssklower /* 30345895Ssklower * Add default listener at end, any others at start. 30445895Ssklower */ 30545895Ssklower if (lcp -> lcd_ceaddr -> x25_udlen == 0) { 30645895Ssklower for (pp = &pk_listenhead; *pp; ) 30745895Ssklower pp = &((*pp) -> lcd_listen); 30845895Ssklower *pp = lcp; 30945895Ssklower } else { 31045895Ssklower lcp -> lcd_listen = pk_listenhead; 31145895Ssklower pk_listenhead = lcp; 31245895Ssklower } 31345895Ssklower return (0); 31445895Ssklower } 31545895Ssklower /* 31645895Ssklower * Include a listening control block for the benefit of other protocols. 31745895Ssklower */ 31845895Ssklower pk_protolisten (spi, spilen, callee) 31947271Ssklower int (*callee) (); 32045895Ssklower { 32145895Ssklower register struct pklcd *lcp = pk_attach ((struct socket *)0); 32245895Ssklower register struct mbuf *nam; 32345895Ssklower register struct sockaddr_x25 *sa; 32445895Ssklower int error = ENOBUFS; 32545895Ssklower 32645895Ssklower if (lcp) { 32747271Ssklower if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) { 32847271Ssklower sa = mtod (nam, struct sockaddr_x25 *); 32945895Ssklower sa -> x25_family = AF_CCITT; 33045895Ssklower sa -> x25_len = nam -> m_len = sizeof (*sa); 33145895Ssklower sa -> x25_udlen = spilen; 33245895Ssklower sa -> x25_udata[0] = spi; 33345895Ssklower lcp -> lcd_upper = callee; 33445895Ssklower lcp -> lcd_flags = X25_MBS_HOLD; 33545895Ssklower error = pk_bind (lcp, nam) || pk_listen (lcp); 33645895Ssklower (void) m_free (nam); 33745895Ssklower } 33845895Ssklower if (error) 33947271Ssklower pk_freelcd (lcp); 34045895Ssklower } 34145895Ssklower return error; /* Hopefully Zero !*/ 34245895Ssklower } 34345895Ssklower 34445895Ssklower /* 34541593Ssklower * Associate a logical channel descriptor with a network. 34641593Ssklower * Fill in the default network specific parameters and then 34741593Ssklower * set any parameters explicitly specified by the user or 34841593Ssklower * by the remote DTE. 34941593Ssklower */ 35041593Ssklower 35141593Ssklower pk_assoc (pkp, lcp, sa) 35241593Ssklower register struct pkcb *pkp; 35341593Ssklower register struct pklcd *lcp; 35441593Ssklower register struct sockaddr_x25 *sa; 35541593Ssklower { 35641593Ssklower 35741593Ssklower lcp -> lcd_pkp = pkp; 35841593Ssklower lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize; 35941593Ssklower lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize; 36041593Ssklower lcp -> lcd_rsn = MODULUS - 1; 36141593Ssklower pkp -> pk_chan[lcp -> lcd_lcn] = lcp; 36241593Ssklower 36341593Ssklower if (sa -> x25_opts.op_psize) 36441593Ssklower lcp -> lcd_packetsize = sa -> x25_opts.op_psize; 36541593Ssklower else 36641593Ssklower sa -> x25_opts.op_psize = lcp -> lcd_packetsize; 36741593Ssklower if (sa -> x25_opts.op_wsize) 36841593Ssklower lcp -> lcd_windowsize = sa -> x25_opts.op_wsize; 36941593Ssklower else 37041593Ssklower sa -> x25_opts.op_wsize = lcp -> lcd_windowsize; 37145165Ssklower sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net; 37241593Ssklower lcp -> lcd_flags = sa -> x25_opts.op_flags; 37341593Ssklower lcp -> lcd_stime = time.tv_sec; 37441593Ssklower } 37541593Ssklower 37645895Ssklower pk_connect (lcp, sa) 37741593Ssklower register struct pklcd *lcp; 37842277Ssklower register struct sockaddr_x25 *sa; 37941593Ssklower { 38041593Ssklower register struct pkcb *pkp; 38141593Ssklower 38241593Ssklower if (sa -> x25_addr[0] == '\0') 38341593Ssklower return (EDESTADDRREQ); 38445297Ssklower if (lcp -> lcd_pkp == 0) 38545297Ssklower for (pkp = pkcbhead; ; pkp = pkp -> pk_next) { 38641593Ssklower if (pkp == 0) 38741593Ssklower return (ENETUNREACH); 38841593Ssklower /* 38941593Ssklower * use first net configured (last in list 39041593Ssklower * headed by pkcbhead) if net is zero 39141593Ssklower */ 39241593Ssklower if (sa -> x25_net == 0 && pkp -> pk_next == 0) 39341593Ssklower break; 39445165Ssklower if (sa -> x25_net == pkp -> pk_xcp -> xc_addr.x25_net) 39541593Ssklower break; 39641593Ssklower } 39741593Ssklower 39841593Ssklower if (pkp -> pk_state != DTE_READY) 39941593Ssklower return (ENETDOWN); 40041593Ssklower if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0) 40141593Ssklower return (EMFILE); 40242277Ssklower lcp -> lcd_faddr = *sa; 40345297Ssklower lcp -> lcd_ceaddr = & lcp -> lcd_faddr; 40441593Ssklower pk_assoc (pkp, lcp, lcp -> lcd_ceaddr); 40545165Ssklower if (lcp -> lcd_so) 40642140Ssklower soisconnecting (lcp -> lcd_so); 40741593Ssklower lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); 40842277Ssklower pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); 40947271Ssklower return (*pkp -> pk_start) (lcp); 41041593Ssklower } 41141593Ssklower 41241593Ssklower /* 41341593Ssklower * Build the rest of the CALL REQUEST packet. Fill in calling 41441593Ssklower * address, facilities fields and the user data field. 41541593Ssklower */ 41641593Ssklower 41742277Ssklower pk_callrequest (lcp, sa, xcp) 41841593Ssklower struct pklcd *lcp; 41942277Ssklower register struct sockaddr_x25 *sa; 42041593Ssklower register struct x25config *xcp; 42141593Ssklower { 42241593Ssklower register struct x25_calladdr *a; 42345895Ssklower register struct mbuf *m = lcp -> lcd_template; 42447271Ssklower register struct x25_packet *xp = mtod (m, struct x25_packet *); 42541593Ssklower unsigned posn = 0; 42641593Ssklower octet *cp; 42741593Ssklower 42845574Ssklower if (lcp -> lcd_flags & X25_DBIT) 42945895Ssklower xp -> d_bit = 1; 43045895Ssklower a = (struct x25_calladdr *) &xp -> packet_data; 43145165Ssklower a -> calling_addrlen = strlen (xcp -> xc_addr.x25_addr); 43241593Ssklower a -> called_addrlen = strlen (sa -> x25_addr); 43341593Ssklower cp = (octet *) a -> address_field; 43441593Ssklower to_bcd (&cp, (int)a -> called_addrlen, sa -> x25_addr, &posn); 43545165Ssklower to_bcd (&cp, (int)a -> calling_addrlen, xcp -> xc_addr.x25_addr, &posn); 43641593Ssklower if (posn & 0x01) 43741593Ssklower *cp++ &= 0xf0; 43845895Ssklower m -> m_len += cp - (octet *) a; 43941593Ssklower 44045895Ssklower if (lcp -> lcd_facilities) { 44147271Ssklower m -> m_pkthdr.len += 44247271Ssklower (m -> m_next = lcp -> lcd_facilities) -> m_len; 44345895Ssklower lcp -> lcd_facilities = 0; 44445895Ssklower } else 44545895Ssklower build_facilities (m, sa, (int)xcp -> xc_type); 44641593Ssklower 44747271Ssklower m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata); 44841593Ssklower #ifdef ANDREW 44941593Ssklower printf ("call: "); 45045297Ssklower for (cp = mtod (m, octet *), posn = 0; posn < m -> m_len; ++posn) 45141593Ssklower printf ("%x ", *cp++); 45241593Ssklower printf ("\n"); 45341593Ssklower #endif 45441593Ssklower } 45541593Ssklower 45647271Ssklower static 45745895Ssklower build_facilities (m, sa, type) 45845895Ssklower register struct mbuf *m; 45941593Ssklower struct sockaddr_x25 *sa; 46041593Ssklower { 46145895Ssklower register octet *cp; 46241593Ssklower register octet *fcp; 46341593Ssklower register int revcharge; 46441593Ssklower 46547271Ssklower cp = mtod (m, octet *) + m -> m_len; 46645895Ssklower fcp = cp + 1; 46741593Ssklower revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0; 46841593Ssklower /* 46941593Ssklower * This is specific to Datapac X.25(1976) DTEs. International 47041593Ssklower * calls must have the "hi priority" bit on. 47141593Ssklower */ 47241593Ssklower if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128) 47341593Ssklower revcharge |= 02; 47441593Ssklower if (revcharge) { 47541593Ssklower *fcp++ = FACILITIES_REVERSE_CHARGE; 47641593Ssklower *fcp++ = revcharge; 47741593Ssklower } 47841593Ssklower switch (type) { 47941593Ssklower case X25_1980: 48041593Ssklower case X25_1984: 48141593Ssklower *fcp++ = FACILITIES_PACKETSIZE; 48241593Ssklower *fcp++ = sa -> x25_opts.op_psize; 48341593Ssklower *fcp++ = sa -> x25_opts.op_psize; 48441593Ssklower 48541593Ssklower *fcp++ = FACILITIES_WINDOWSIZE; 48641593Ssklower *fcp++ = sa -> x25_opts.op_wsize; 48741593Ssklower *fcp++ = sa -> x25_opts.op_wsize; 48841593Ssklower } 48945895Ssklower *cp = fcp - cp - 1; 49045895Ssklower m -> m_pkthdr.len = (m -> m_len += *cp + 1); 49141593Ssklower } 49241593Ssklower 49341593Ssklower to_bcd (a, len, x, posn) 49441593Ssklower register octet **a; 49541593Ssklower register char *x; 49641593Ssklower register int len; 49741593Ssklower register unsigned *posn; 49841593Ssklower { 49941593Ssklower while (--len >= 0) 50041593Ssklower if ((*posn)++ & 0x01) 50141593Ssklower *(*a)++ |= *x++ & 0x0F; 50241593Ssklower else 50341593Ssklower **a = *x++ << 4; 50441593Ssklower } 50541593Ssklower 50641593Ssklower /* 50741593Ssklower * This routine gets the first available logical channel number. The 50841593Ssklower * search is from the highest number to lowest number (DTE). 50941593Ssklower */ 51041593Ssklower 51141593Ssklower pk_getlcn (pkp) 51241593Ssklower register struct pkcb *pkp; 51341593Ssklower { 51441593Ssklower register int i; 51541593Ssklower 51645297Ssklower if (pkp -> pk_chan == 0) 51742140Ssklower return (0); 51841593Ssklower for (i = pkp -> pk_maxlcn; i > 0; --i) 51941593Ssklower if (pkp -> pk_chan[i] == NULL) 52041593Ssklower break; 52141593Ssklower return (i); 52241593Ssklower 52341593Ssklower } 52441593Ssklower 52541593Ssklower /* 52641593Ssklower * This procedure sends a CLEAR request packet. The lc state is 52741593Ssklower * set to "SENT_CLEAR". 52841593Ssklower */ 52941593Ssklower 53045895Ssklower pk_clear (lcp, diagnostic, abortive) 53145895Ssklower register struct pklcd *lcp; 53241593Ssklower { 53345895Ssklower register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR); 53441593Ssklower 53545895Ssklower m -> m_len += 2; 53647271Ssklower mtod (m, struct x25_packet *) -> packet_data = 0; 53747271Ssklower mtod (m, octet *)[4] = diagnostic; 53845895Ssklower if (lcp -> lcd_facilities) { 53945895Ssklower m -> m_next = lcp -> lcd_facilities; 54045895Ssklower m -> m_pkthdr.len += m -> m_next -> m_len; 54145895Ssklower lcp -> lcd_facilities = 0; 54245895Ssklower } 54345895Ssklower if (abortive) 54445895Ssklower lcp -> lcd_template = m; 54545895Ssklower else { 54645895Ssklower struct socket *so = lcp -> lcd_so; 54745895Ssklower struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb; 54847271Ssklower sbappendrecord (sb, m); 54945895Ssklower } 55041593Ssklower pk_output (lcp); 55141593Ssklower 55241593Ssklower } 55341593Ssklower 55447271Ssklower /* 55547271Ssklower * This procedure generates RNR's or RR's to inhibit or enable 55647271Ssklower * inward data flow, if the current state changes (blocked ==> open or 55747271Ssklower * vice versa), or if forced to generate one. One forces RNR's to ack data. 55847271Ssklower */ 55947271Ssklower pk_flowcontrol (lcp, inhibit, forced) 56047271Ssklower register struct pklcd *lcp; 56147271Ssklower { 56247271Ssklower inhibit = (inhibit != 0); 56347271Ssklower if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER || 56447271Ssklower (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit)) 56547271Ssklower return; 56647271Ssklower lcp -> lcd_rxrnr_condition = inhibit; 56747271Ssklower lcp -> lcd_template = pk_template (lcp -> lcd_lcn, inhibit ? RNR : RR); 56847271Ssklower pk_output (lcp); 56947271Ssklower } 57047271Ssklower 57141593Ssklower /* 57247271Ssklower * This procedure sends a RESET request packet. It re-intializes 57341593Ssklower * virtual circuit. 57441593Ssklower */ 57541593Ssklower 57641593Ssklower static 57745895Ssklower pk_reset (lcp, diagnostic) 57841593Ssklower register struct pklcd *lcp; 57941593Ssklower { 58045895Ssklower register struct mbuf *m; 58145895Ssklower register struct socket *so = lcp -> lcd_so; 58241593Ssklower 58341593Ssklower if (lcp -> lcd_state != DATA_TRANSFER) 58441593Ssklower return; 58541593Ssklower 58645895Ssklower if (so) 58745895Ssklower so -> so_error = ECONNRESET; 58841593Ssklower lcp -> lcd_reset_condition = TRUE; 58941593Ssklower 59041593Ssklower /* Reset all the control variables for the channel. */ 59145895Ssklower pk_flush (lcp); 59241593Ssklower lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = 59341593Ssklower lcp -> lcd_intrconf_pending = FALSE; 59441593Ssklower lcp -> lcd_rsn = MODULUS - 1; 59541593Ssklower lcp -> lcd_ssn = 0; 59641593Ssklower lcp -> lcd_output_window = lcp -> lcd_input_window = 59741593Ssklower lcp -> lcd_last_transmitted_pr = 0; 59845895Ssklower m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET); 59945895Ssklower m -> m_len += 2; 60047271Ssklower mtod (m, struct x25_packet *) -> packet_data = 0; 60147271Ssklower mtod (m, octet *)[4] = diagnostic; 60245895Ssklower pk_output (lcp); 60345895Ssklower 60445895Ssklower } 60545895Ssklower 60645895Ssklower /* 60745895Ssklower * This procedure frees all data queued for output or delivery on a 60845895Ssklower * virtual circuit. 60945895Ssklower */ 61045895Ssklower 61145895Ssklower pk_flush (lcp) 61245895Ssklower register struct pklcd *lcp; 61345895Ssklower { 61445895Ssklower register struct socket *so; 61545895Ssklower 61645895Ssklower if (lcp -> lcd_template) 61745895Ssklower m_freem (lcp -> lcd_template); 61845895Ssklower 61945895Ssklower if (lcp -> lcd_cps) { 62047271Ssklower m_freem (lcp -> lcd_cps); 62145895Ssklower lcp -> lcd_cps = 0; 62245895Ssklower } 62347271Ssklower if (lcp -> lcd_facilities) { 62447271Ssklower m_freem (lcp -> lcd_facilities); 62547271Ssklower lcp -> lcd_facilities = 0; 62647271Ssklower } 62747271Ssklower if (so = lcp -> lcd_so) { 62842140Ssklower sbflush (&so -> so_rcv); 62942140Ssklower sbflush (&so -> so_snd); 63045895Ssklower } else 63145895Ssklower sbflush (&lcp -> lcd_sb); 63241593Ssklower } 63341593Ssklower 63441593Ssklower /* 63541593Ssklower * This procedure handles all local protocol procedure errors. 63641593Ssklower */ 63741593Ssklower 63845895Ssklower pk_procerror (error, lcp, errstr, diagnostic) 63941593Ssklower register struct pklcd *lcp; 64041593Ssklower char *errstr; 64141593Ssklower { 64241593Ssklower 64341593Ssklower pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr); 64441593Ssklower 64541593Ssklower switch (error) { 64641593Ssklower case CLEAR: 64745297Ssklower if (lcp -> lcd_so) { 64845297Ssklower lcp -> lcd_so -> so_error = ECONNABORTED; 64945297Ssklower soisdisconnecting (lcp -> lcd_so); 65041593Ssklower } 65145895Ssklower pk_clear (lcp, diagnostic, 1); 65241593Ssklower break; 65341593Ssklower 65441593Ssklower case RESET: 65545895Ssklower pk_reset (lcp, diagnostic); 65641593Ssklower } 65741593Ssklower } 65841593Ssklower 65941593Ssklower /* 66041593Ssklower * This procedure is called during the DATA TRANSFER state to check 66141593Ssklower * and process the P(R) values received in the DATA, RR OR RNR 66241593Ssklower * packets. 66341593Ssklower */ 66441593Ssklower 66541593Ssklower pk_ack (lcp, pr) 66641593Ssklower struct pklcd *lcp; 66741593Ssklower unsigned pr; 66841593Ssklower { 66941593Ssklower register struct socket *so = lcp -> lcd_so; 67041593Ssklower 67141593Ssklower if (lcp -> lcd_output_window == pr) 67241593Ssklower return (PACKET_OK); 67341593Ssklower if (lcp -> lcd_output_window < lcp -> lcd_ssn) { 67441593Ssklower if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) { 67545895Ssklower pk_procerror (RESET, lcp, 67645895Ssklower "p(r) flow control error", 2); 67741593Ssklower return (ERROR_PACKET); 67841593Ssklower } 67941593Ssklower } 68041593Ssklower else { 68141593Ssklower if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) { 68245895Ssklower pk_procerror (RESET, lcp, 68347271Ssklower "p(r) flow control error #2", 2); 68441593Ssklower return (ERROR_PACKET); 68541593Ssklower } 68641593Ssklower } 68741593Ssklower 68841593Ssklower lcp -> lcd_output_window = pr; /* Rotate window. */ 68941593Ssklower if (lcp -> lcd_window_condition == TRUE) 69041593Ssklower lcp -> lcd_window_condition = FALSE; 69141593Ssklower 69242140Ssklower if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel)) 69341593Ssklower sowwakeup (so); 69443361Ssklower if (lcp -> lcd_upper) 69547271Ssklower (*lcp -> lcd_upper) (lcp, 0); 69641593Ssklower 69741593Ssklower return (PACKET_OK); 69841593Ssklower } 69941593Ssklower 70041593Ssklower /* 70141593Ssklower * This procedure decodes the X.25 level 3 packet returning a 70241593Ssklower * code to be used in switchs or arrays. 70341593Ssklower */ 70441593Ssklower 70541593Ssklower pk_decode (xp) 70641593Ssklower register struct x25_packet *xp; 70741593Ssklower { 70841593Ssklower register int type; 70941593Ssklower 71041593Ssklower if (xp -> fmt_identifier != 1) 71141593Ssklower return (INVALID_PACKET); 71245895Ssklower #ifdef ancient_history 71341593Ssklower /* 71441593Ssklower * Make sure that the logical channel group number is 0. 71541593Ssklower * This restriction may be removed at some later date. 71641593Ssklower */ 71741593Ssklower if (xp -> lc_group_number != 0) 71841593Ssklower return (INVALID_PACKET); 71945895Ssklower #endif 72041593Ssklower /* 72141593Ssklower * Test for data packet first. 72241593Ssklower */ 72341593Ssklower if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR)) 72441593Ssklower return (DATA); 72541593Ssklower 72641593Ssklower /* 72741593Ssklower * Test if flow control packet (RR or RNR). 72841593Ssklower */ 72941593Ssklower if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR)) 73047271Ssklower switch (xp -> packet_type & 0x1f) { 73147271Ssklower case X25_RR: 73241593Ssklower return (RR); 73347271Ssklower case X25_RNR: 73441593Ssklower return (RNR); 73547271Ssklower case X25_REJECT: 73647271Ssklower return (REJECT); 73747271Ssklower } 73841593Ssklower 73941593Ssklower /* 74041593Ssklower * Determine the rest of the packet types. 74141593Ssklower */ 74241593Ssklower switch (xp -> packet_type) { 74341593Ssklower case X25_CALL: 74441593Ssklower type = CALL; 74541593Ssklower break; 74641593Ssklower 74741593Ssklower case X25_CALL_ACCEPTED: 74841593Ssklower type = CALL_ACCEPTED; 74941593Ssklower break; 75041593Ssklower 75141593Ssklower case X25_CLEAR: 75241593Ssklower type = CLEAR; 75341593Ssklower break; 75441593Ssklower 75541593Ssklower case X25_CLEAR_CONFIRM: 75641593Ssklower type = CLEAR_CONF; 75741593Ssklower break; 75841593Ssklower 75941593Ssklower case X25_INTERRUPT: 76041593Ssklower type = INTERRUPT; 76141593Ssklower break; 76241593Ssklower 76341593Ssklower case X25_INTERRUPT_CONFIRM: 76441593Ssklower type = INTERRUPT_CONF; 76541593Ssklower break; 76641593Ssklower 76741593Ssklower case X25_RESET: 76841593Ssklower type = RESET; 76941593Ssklower break; 77041593Ssklower 77141593Ssklower case X25_RESET_CONFIRM: 77241593Ssklower type = RESET_CONF; 77341593Ssklower break; 77441593Ssklower 77541593Ssklower case X25_RESTART: 77641593Ssklower type = RESTART; 77741593Ssklower break; 77841593Ssklower 77941593Ssklower case X25_RESTART_CONFIRM: 78041593Ssklower type = RESTART_CONF; 78141593Ssklower break; 78241593Ssklower 78347271Ssklower case X25_DIAGNOSTIC: 78448873Ssklower type = DIAG_TYPE; 78547271Ssklower break; 78647271Ssklower 78741593Ssklower default: 78841593Ssklower type = INVALID_PACKET; 78941593Ssklower } 79041593Ssklower return (type); 79141593Ssklower } 79241593Ssklower 79341593Ssklower /* 79441593Ssklower * A restart packet has been received. Print out the reason 79541593Ssklower * for the restart. 79641593Ssklower */ 79741593Ssklower 79841593Ssklower pk_restartcause (pkp, xp) 79941593Ssklower struct pkcb *pkp; 80041593Ssklower register struct x25_packet *xp; 80141593Ssklower { 80241593Ssklower register struct x25config *xcp = pkp -> pk_xcp; 80345574Ssklower register int lcn = LCN(xp); 80441593Ssklower 80541593Ssklower switch (xp -> packet_data) { 80641593Ssklower case X25_RESTART_LOCAL_PROCEDURE_ERROR: 80741593Ssklower pk_message (lcn, xcp, "restart: local procedure error"); 80841593Ssklower break; 80941593Ssklower 81041593Ssklower case X25_RESTART_NETWORK_CONGESTION: 81141593Ssklower pk_message (lcn, xcp, "restart: network congestion"); 81241593Ssklower break; 81341593Ssklower 81441593Ssklower case X25_RESTART_NETWORK_OPERATIONAL: 81541593Ssklower pk_message (lcn, xcp, "restart: network operational"); 81641593Ssklower break; 81741593Ssklower 81841593Ssklower default: 81941593Ssklower pk_message (lcn, xcp, "restart: unknown cause"); 82041593Ssklower } 82141593Ssklower } 82241593Ssklower 82341593Ssklower #define MAXRESETCAUSE 7 82441593Ssklower 82541593Ssklower int Reset_cause[] = { 82641593Ssklower EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG 82741593Ssklower }; 82841593Ssklower 82941593Ssklower /* 83041593Ssklower * A reset packet has arrived. Return the cause to the user. 83141593Ssklower */ 83241593Ssklower 83341593Ssklower pk_resetcause (pkp, xp) 83441593Ssklower struct pkcb *pkp; 83541593Ssklower register struct x25_packet *xp; 83641593Ssklower { 83745297Ssklower register struct pklcd *lcp = 83845574Ssklower pkp -> pk_chan[LCN(xp)]; 83941593Ssklower register int code = xp -> packet_data; 84041593Ssklower 84141593Ssklower if (code > MAXRESETCAUSE) 84241593Ssklower code = 7; /* EXRNCG */ 84341593Ssklower 84447271Ssklower pk_message(LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x", 84547271Ssklower xp -> packet_data, 4[(u_char *)xp]); 84647271Ssklower 84745297Ssklower lcp -> lcd_so -> so_error = Reset_cause[code]; 84841593Ssklower } 84941593Ssklower 85041593Ssklower #define MAXCLEARCAUSE 25 85141593Ssklower 85241593Ssklower int Clear_cause[] = { 85341593Ssklower EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0, 85441593Ssklower 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE, 85541593Ssklower 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC 85641593Ssklower }; 85741593Ssklower 85841593Ssklower /* 85941593Ssklower * A clear packet has arrived. Return the cause to the user. 86041593Ssklower */ 86141593Ssklower 86241593Ssklower pk_clearcause (pkp, xp) 86341593Ssklower struct pkcb *pkp; 86441593Ssklower register struct x25_packet *xp; 86541593Ssklower { 86645297Ssklower register struct pklcd *lcp = 86745574Ssklower pkp -> pk_chan[LCN(xp)]; 86841593Ssklower register int code = xp -> packet_data; 86941593Ssklower 87041593Ssklower if (code > MAXCLEARCAUSE) 87141593Ssklower code = 5; /* EXRNCG */ 87245297Ssklower lcp -> lcd_so -> so_error = Clear_cause[code]; 87341593Ssklower } 87441593Ssklower 87541593Ssklower char * 87641593Ssklower format_ntn (xcp) 87741593Ssklower register struct x25config *xcp; 87841593Ssklower { 87941593Ssklower 88045165Ssklower return (xcp -> xc_addr.x25_addr); 88141593Ssklower } 88241593Ssklower 88341593Ssklower /* VARARGS1 */ 88441593Ssklower pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6) 88541593Ssklower struct x25config *xcp; 88641593Ssklower char *fmt; 88741593Ssklower { 88841593Ssklower 88941593Ssklower if (lcn) 89041593Ssklower if (pkcbhead -> pk_next) 89141593Ssklower printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn); 89241593Ssklower else 89341593Ssklower printf ("X.25: lcn %d: ", lcn); 89441593Ssklower else 89541593Ssklower if (pkcbhead -> pk_next) 89641593Ssklower printf ("X.25(%s): ", format_ntn (xcp)); 89741593Ssklower else 89841593Ssklower printf ("X.25: "); 89941593Ssklower 90041593Ssklower printf (fmt, a1, a2, a3, a4, a5, a6); 90141593Ssklower printf ("\n"); 90241593Ssklower } 90345297Ssklower 90447271Ssklower pk_ifattach (ia, lloutput, llnext) 90545297Ssklower register struct x25_ifaddr *ia; 90647271Ssklower int (*lloutput) (); 90745297Ssklower caddr_t llnext; 90845297Ssklower { 90945297Ssklower /* this is here because you can't include both pk_var and hd_var */ 91045297Ssklower /* this will probably be replace by a streams gluing mechanism */ 91145297Ssklower ia -> ia_pkcb.pk_lloutput = lloutput; 91245297Ssklower ia -> ia_pkcb.pk_llnext = llnext; 91345297Ssklower } 91445297Ssklower 91547271Ssklower pk_fragment (lcp, m0, qbit, mbit, wait) 91645297Ssklower struct mbuf *m0; 91745297Ssklower register struct pklcd *lcp; 91845297Ssklower { 91945297Ssklower register struct mbuf *m = m0; 92045297Ssklower register struct x25_packet *xp; 92145297Ssklower register struct sockbuf *sb; 92247271Ssklower struct mbuf *head = 0, *next, **mp = &head, *m_split (); 92345297Ssklower int totlen, psize = 1 << (lcp -> lcd_packetsize); 92445297Ssklower 92545297Ssklower if (m == 0) 92645297Ssklower return; 92745895Ssklower if (m -> m_flags & M_PKTHDR == 0) 92847271Ssklower panic ("pk_fragment"); 92945297Ssklower totlen = m -> m_pkthdr.len; 93045574Ssklower m -> m_act = 0; 93145297Ssklower sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb; 93245297Ssklower do { 93345297Ssklower if (totlen > psize) { 93447271Ssklower if ((next = m_split (m, psize, wait)) == 0) 93545297Ssklower goto abort; 93645297Ssklower totlen -= psize; 93745574Ssklower } else 93845574Ssklower next = 0; 93945297Ssklower M_PREPEND(m, PKHEADERLN, wait); 94045297Ssklower if (m == 0) 94145297Ssklower goto abort; 94245574Ssklower *mp = m; 94345574Ssklower mp = & m -> m_act; 94445574Ssklower *mp = 0; 94547271Ssklower xp = mtod (m, struct x25_packet *); 94645297Ssklower 0[(char *)xp] = 0; 94745297Ssklower if (qbit) 94845574Ssklower xp -> q_bit = 1; 94945574Ssklower if (lcp -> lcd_flags & X25_DBIT) 95045574Ssklower xp -> d_bit = 1; 95145297Ssklower xp -> fmt_identifier = 1; 95245297Ssklower xp -> packet_type = X25_DATA; 95345574Ssklower SET_LCN(xp, lcp -> lcd_lcn); 95445574Ssklower if (next || (mbit && (totlen == psize || 95545574Ssklower (lcp -> lcd_flags & X25_DBIT)))) 95645297Ssklower MBIT(xp) = 1; 95745297Ssklower } while (m = next); 95845574Ssklower for (m = head; m; m = next) { 95945297Ssklower next = m -> m_act; 96045297Ssklower m -> m_act = 0; 96147271Ssklower sbappendrecord (sb, m); 96245297Ssklower } 96345297Ssklower return 0; 96445297Ssklower abort: 96545574Ssklower if (wait) 96647271Ssklower panic ("pk_fragment null mbuf after wait"); 96745574Ssklower if (next) 96847271Ssklower m_freem (next); 96945574Ssklower for (m = head; m; m = next) { 97045297Ssklower next = m -> m_act; 97147271Ssklower m_freem (m); 97245297Ssklower } 97345297Ssklower return ENOBUFS; 97445297Ssklower } 97545574Ssklower 97645574Ssklower struct mbuf * 97747271Ssklower m_split (m0, len0, wait) 97845574Ssklower register struct mbuf *m0; 97945574Ssklower int len0; 98045574Ssklower { 98145574Ssklower register struct mbuf *m, *n; 98245574Ssklower unsigned len = len0; 98345574Ssklower 98445574Ssklower for (m = m0; m && len > m -> m_len; m = m -> m_next) 98545574Ssklower len -= m -> m_len; 98645574Ssklower if (m == 0) 98745574Ssklower return (0); 98845574Ssklower if (m0 -> m_flags & M_PKTHDR) { 98945574Ssklower MGETHDR(n, wait, m0 -> m_type); 99045574Ssklower if (n == 0) 99145574Ssklower return (0); 99245574Ssklower n -> m_pkthdr.rcvif = m0 -> m_pkthdr.rcvif; 99345574Ssklower n -> m_pkthdr.len = m0 -> m_pkthdr.len - len0; 99445574Ssklower m0 -> m_pkthdr.len = len0; 99545574Ssklower if (m -> m_flags & M_EXT) 99645574Ssklower goto extpacket; 99745574Ssklower if (len > MHLEN) { 99845574Ssklower /* m can't be the lead packet */ 99945574Ssklower MH_ALIGN(n, 0); 100047271Ssklower n -> m_next = m_split (m, len, wait); 100145574Ssklower if (n -> m_next == 0) { 100247271Ssklower (void) m_free (n); 100345574Ssklower return (0); 100445574Ssklower } else 100545574Ssklower return (n); 100645574Ssklower } else 100745574Ssklower MH_ALIGN(n, len); 100845574Ssklower } else if (len == m -> m_len) { 100945574Ssklower n = m -> m_next; 101045574Ssklower m -> m_next = 0; 101145574Ssklower return (n); 101245574Ssklower } 101345574Ssklower extpacket: 101445574Ssklower len = m -> m_len - len; /* remainder to be copied */ 101545574Ssklower m -> m_len -= len; /* now equals original len */ 101645895Ssklower if (m -> m_flags & M_EXT) { 101745574Ssklower n -> m_flags |= M_EXT; 101845574Ssklower n -> m_ext = m -> m_ext; 101947271Ssklower mclrefcnt[mtocl (m -> m_ext.ext_buf)]++; 102045574Ssklower n -> m_data = m -> m_data + m -> m_len; 102145574Ssklower } else { 102245574Ssklower MGET(n, wait, m -> m_type); 102345574Ssklower if (n == 0) { 102445574Ssklower m -> m_len += len; 102545574Ssklower return (0); 102645574Ssklower } 102745574Ssklower M_ALIGN(n, len); 102847271Ssklower bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len); 102945574Ssklower } 103045574Ssklower n -> m_len = len; 103145574Ssklower n -> m_next = m -> m_next; 103245574Ssklower m -> m_next = 0; 103345574Ssklower return (n); 103445574Ssklower } 1035