/* * * =================================== * HARP | Host ATM Research Platform * =================================== * * * This Host ATM Research Platform ("HARP") file (the "Software") is * made available by Network Computing Services, Inc. ("NetworkCS") * "AS IS". NetworkCS does not provide maintenance, improvements or * support of any kind. * * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. * In no event shall NetworkCS be responsible for any damages, including * but not limited to consequential damages, arising from or relating to * any use of the Software or related support. * * Copyright 1994-1998 Network Computing Services, Inc. * * Copies of this Software may be made, however, the above copyright * notice must be reproduced on all copies. * * @(#) $FreeBSD$ * */ /* * ATM Forum UNI 3.0/3.1 Signalling Manager * ---------------------------------------- * * Message buffer handling routines * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef lint __RCSID("@(#) $FreeBSD$"); #endif /* * Initialize a unisig formatting structure * * Arguments: * usf pointer to a unisig formatting structure * usp pointer to a unisig protocol instance * buf pointer to a buffer chain (decode only) * op operation code (encode or decode) * headroom headroom to leave in first buffer * * Returns: * 0 success * errno error encountered * */ int usf_init(usf, usp, buf, op, headroom) struct usfmt *usf; struct unisig *usp; KBuffer *buf; int op; int headroom; { KBuffer *m; ATM_DEBUG3("usf_init: usf=%p, buf=%p, op=%d\n", usf, buf, op); /* * Check parameters */ if (!usf) return(EINVAL); switch(op) { case USF_ENCODE: /* * Get a buffer */ KB_ALLOCPKT(m, USF_MIN_ALLOC, KB_F_NOWAIT, KB_T_DATA); if (m == NULL) return(ENOMEM); KB_LEN(m) = 0; if (headroom < KB_BFRLEN(m)) { KB_HEADSET(m, headroom); } break; case USF_DECODE: /* * Verify buffer address */ if (!buf) return(EINVAL); m = buf; break; default: return(EINVAL); } /* * Save parameters in formatting structure */ usf->usf_m_addr = m; usf->usf_m_base = m; usf->usf_loc = 0; usf->usf_op = op; usf->usf_sig = usp; return(0); } /* * Get or put the next byte of a signalling message * * Arguments: * usf pointer to a unisig formatting structure * c pointer to the byte to send from or receive into * * Returns: * 0 success * errno error encountered * */ int usf_byte(usf, c) struct usfmt *usf; u_char *c; { u_char *mp; KBuffer *m = usf->usf_m_addr, *m1; int space; switch (usf->usf_op) { case USF_DECODE: /* * Make sure we're not past the end of the buffer * (allowing for zero-length buffers) */ while (usf->usf_loc >= KB_LEN(m)) { if (KB_NEXT(usf->usf_m_addr)) { usf->usf_m_addr = m = KB_NEXT(usf->usf_m_addr); usf->usf_loc = 0; } else { return(EMSGSIZE); } } /* * Get the data from the buffer */ KB_DATASTART(m, mp, u_char *); *c = mp[usf->usf_loc]; usf->usf_loc++; break; case USF_ENCODE: /* * If the current buffer is full, get another */ KB_TAILROOM(m, space); if (space == 0) { KB_ALLOC(m1, USF_MIN_ALLOC, KB_F_NOWAIT, KB_T_DATA); if (m1 == NULL) return(ENOMEM); KB_LEN(m1) = 0; KB_LINK(m1, m); usf->usf_m_addr = m = m1; usf->usf_loc = 0; } /* * Put the data into the buffer */ KB_DATASTART(m, mp, u_char *); mp[usf->usf_loc] = *c; KB_TAILADJ(m, 1); usf->usf_loc++; break; default: /* * Invalid operation code */ return(EINVAL); } return(0); } /* * Get or put a short integer * * Arguments: * usf pointer to a unisig formatting structure * s pointer to a short to send from or receive into * * Returns: * 0 success * errno error encountered * */ int usf_short(usf, s) struct usfmt *usf; u_short *s; { int rc; union { u_short value; u_char b[sizeof(u_short)]; } tval; tval.value = 0; if (usf->usf_op == USF_ENCODE) tval.value = htons(*s); if ((rc = usf_byte(usf, &tval.b[0])) != 0) return(rc); if ((rc = usf_byte(usf, &tval.b[1])) != 0) return(rc); if (usf->usf_op == USF_DECODE) *s = ntohs(tval.value); return(0); } /* * Get or put a 3-byte integer * * Arguments: * usf pointer to a unisig formatting structure * i pointer to an integer to send from or receive into * * Returns: * 0 success * errno error encountered * */ int usf_int3(usf, i) struct usfmt *usf; u_int *i; { int j, rc; union { u_int value; u_char b[sizeof(u_int)]; } tval; tval.value = 0; if (usf->usf_op == USF_ENCODE) tval.value = htonl(*i); for (j=0; j<3; j++) { rc = usf_byte(usf, &tval.b[j+sizeof(u_int)-3]); if (rc) return(rc); } if (usf->usf_op == USF_DECODE) *i = ntohl(tval.value); return(rc); } /* * Get or put an integer * * Arguments: * usf pointer to a unisig formatting structure * i pointer to an integer to send from or receive into * * Returns: * 0 success * errno error encountered * */ int usf_int(usf, i) struct usfmt *usf; u_int *i; { int j, rc; union { u_int value; u_char b[sizeof(u_int)]; } tval; if (usf->usf_op == USF_ENCODE) tval.value = htonl(*i); for (j=0; j<4; j++) { rc = usf_byte(usf, &tval.b[j+sizeof(u_int)-4]); if (rc) return(rc); } if (usf->usf_op == USF_DECODE) *i = ntohl(tval.value); return(rc); } /* * Get or put an extented field * * An extented field consists of a string of bytes. All but the last * byte of the field has the high-order bit set to zero. When decoding, * this routine will read bytes until either the input is exhausted or * a byte with a high-order one is found. Whe encoding, it will take an * unsigned integer and write until the highest-order one bit has been * written. * * Arguments: * usf pointer to a unisig formatting structure * i pointer to an integer to send from or receive into * * Returns: * 0 success * errno error encountered * */ int usf_ext(usf, i) struct usfmt *usf; u_int *i; { int j, rc; u_char c, buff[sizeof(u_int)+1]; u_int val; union { u_int value; u_char b[sizeof(u_int)]; } tval; switch(usf->usf_op) { case USF_ENCODE: val = *i; j = 0; while (val) { tval.value = htonl(val); buff[j] = tval.b[sizeof(u_int)-1] & UNI_IE_EXT_MASK; val >>= 7; j++; } j--; buff[0] |= UNI_IE_EXT_BIT; for (; j>=0; j--) { rc = usf_byte(usf, &buff[j]); if (rc) return(rc); } break; case USF_DECODE: c = 0; val = 0; while (!(c & UNI_IE_EXT_BIT)) { rc = usf_byte(usf, &c); if (rc) return(rc); val = (val << 7) + (c & UNI_IE_EXT_MASK); } *i = val; break; default: return(EINVAL); } return(0); } /* * Count the bytes remaining to be decoded * * Arguments: * usf pointer to a unisig formatting structure * * Returns: * int the number of bytes in the buffer chain remaining to * be decoded * */ int usf_count(usf) struct usfmt *usf; { int count; KBuffer *m = usf->usf_m_addr; /* * Return zero if we're not decoding */ if (usf->usf_op != USF_DECODE) return (0); /* * Calculate the length of data remaining in the current buffer */ count = KB_LEN(m) - usf->usf_loc; /* * Loop through any remaining buffers, adding in their lengths */ while (KB_NEXT(m)) { m = KB_NEXT(m); count += KB_LEN(m); } return(count); } /* * Get or put the next byte of a signalling message and return * the byte's buffer address * * Arguments: * usf pointer to a unisig formatting structure * c pointer to the byte to send from or receive into * bp address to store the byte's buffer address * * Returns: * 0 success * errno error encountered * */ int usf_byte_mark(usf, c, bp) struct usfmt *usf; u_char *c; u_char **bp; { u_char *mp; int rc; /* * First, get/put the data byte */ rc = usf_byte(usf, c); if (rc) { /* * Error encountered */ *bp = NULL; return (rc); } /* * Now return the buffer address of that byte */ KB_DATASTART(usf->usf_m_addr, mp, u_char *); *bp = &mp[usf->usf_loc - 1]; return (0); }