diff options
Diffstat (limited to 'sys/netatm/ipatm/ipatm_output.c')
-rw-r--r-- | sys/netatm/ipatm/ipatm_output.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/sys/netatm/ipatm/ipatm_output.c b/sys/netatm/ipatm/ipatm_output.c new file mode 100644 index 0000000..7f02f28 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_output.c @@ -0,0 +1,216 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm_output.c,v 1.6 1998/02/19 20:14:17 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Output IP packets across an ATM VCC + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_output.c,v 1.6 1998/02/19 20:14:17 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Output an IP Packet + * + * All IP packets output to an ATM interface will be directed here via + * the atm_ifoutput() function. If there is an ATM VCC already setup for + * the destination IP address, then we'll just send the packet to that VCC. + * Otherwise we will have to setup a new VCC, ARPing for the corresponding + * destination ATM hardware address along the way. + * + * Arguments: + * ifp pointer to ifnet structure + * m pointer to packet buffer chain to be output + * dst pointer to packet's IP destination address + * + * Returns: + * 0 packet "output" was successful + * errno output failed - reason indicated + * + */ +int +ipatm_ifoutput(ifp, m, dst) + struct ifnet *ifp; + KBuffer *m; + struct sockaddr *dst; +{ + struct ipvcc *ivp; + int err = 0; + +#ifdef DIAGNOSTIC + if (ipatm_print) { + atm_pdu_print(m, "ipatm_ifoutput"); + } +#endif + + /* + * See if we've already got an appropriate VCC + */ + ivp = ipatm_iptovc((struct sockaddr_in *)dst, (struct atm_nif *)ifp); + if (ivp) { + + /* + * Reset idle timer + */ + ivp->iv_idle = 0; + + /* + * Can we use this VCC now?? + */ + if ((ivp->iv_state == IPVCC_ACTIVE) && + (ivp->iv_flags & IVF_MAPOK)) { + + /* + * OK, now send packet + */ + err = atm_cm_cpcs_data(ivp->iv_conn, m); + if (err) { + /* + * Output problem, drop packet + */ + KB_FREEALL(m); + } + } else { + + /* + * VCC is unavailable for data packets. Queue packet + * for now, but only maintain a queue length of one. + */ + if (ivp->iv_queue) + KB_FREEALL(ivp->iv_queue); + + ivp->iv_queue = m; + } + } else { + struct in_ifaddr *ia; +#if (defined(BSD) && (BSD < 199306)) + extern struct ifnet loif; +#endif + + /* + * No VCC to destination + */ + + /* + * Is packet for our interface address? + */ + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { + if (ia->ia_ifp != ifp) + continue; + if (((struct sockaddr_in *)dst)->sin_addr.s_addr == + IA_SIN(ia)->sin_addr.s_addr) { + + /* + * It's for us - hand packet to loopback driver + */ + (void) if_simloop(ifp, m, dst, 0); + goto done; + } + } + + /* + * Is this a broadcast packet ?? + */ +#if (defined(BSD) && (BSD >= 199306)) + if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr, ifp)) { +#else + if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) { +#endif + struct ip_nif *inp; + int s; + + /* + * If interface server exists and provides broadcast + * services, then let it deal with this packet + */ + s = splnet(); + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == (struct atm_nif *)ifp) + break; + } + (void) splx(s); + + if ((inp == NULL) || + (inp->inf_serv == NULL) || + (inp->inf_serv->is_bcast_output == NULL)) { + KB_FREEALL(m); + err = EADDRNOTAVAIL; + goto done; + } + + err = (*inp->inf_serv->is_bcast_output)(inp, m); + goto done; + } + + /* + * How about a multicast packet ?? + */ + if (IN_MULTICAST(ntohl(SATOSIN(dst)->sin_addr.s_addr))) { + /* + * Multicast isn't currently supported + */ + KB_FREEALL(m); + err = EADDRNOTAVAIL; + goto done; + } + + /* + * Well, I guess we need to create an SVC to the destination + */ + if ((err = ipatm_createsvc(ifp, AF_INET, + (caddr_t)&((struct sockaddr_in *)dst)->sin_addr, + &ivp)) == 0) { + /* + * SVC open is proceeding, queue packet + */ + ivp->iv_queue = m; + + } else { + /* + * SVC open failed, release buffers and return + */ + KB_FREEALL(m); + } + } + +done: + return (err); +} + |