summaryrefslogtreecommitdiffstats
path: root/sys/netatm/atm_if.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/atm_if.c')
-rw-r--r--sys/netatm/atm_if.c1202
1 files changed, 1202 insertions, 0 deletions
diff --git a/sys/netatm/atm_if.c b/sys/netatm/atm_if.c
new file mode 100644
index 0000000..a07ccc2
--- /dev/null
+++ b/sys/netatm/atm_if.c
@@ -0,0 +1,1202 @@
+/*
+ *
+ * ===================================
+ * 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: atm_if.c,v 1.13 1998/07/23 21:43:55 root Exp $
+ *
+ */
+
+/*
+ * Core ATM Services
+ * -----------------
+ *
+ * ATM interface management
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: atm_if.c,v 1.13 1998/07/23 21:43:55 root Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+
+#if (defined(BSD) && (BSD < 199506))
+extern int ifqmaxlen;
+#endif
+
+/*
+ * Local functions
+ */
+static int atm_physif_ioctl __P((int, caddr_t, caddr_t));
+#if (defined(BSD) && (BSD >= 199306))
+static int atm_netif_rtdel __P((struct radix_node *, void *));
+#endif
+static int atm_if_ioctl __P((struct ifnet *, u_long, caddr_t));
+static int atm_ifparse __P((char *, char *, int, int *));
+
+/*
+ * Local variables
+ */
+static int (*atm_ifouttbl[AF_MAX+1])
+ __P((struct ifnet *, KBuffer *, struct sockaddr *))
+ = {NULL};
+
+
+/*
+ * Register an ATM physical interface
+ *
+ * Each ATM device interface must register itself here upon completing
+ * its internal initialization. This applies to both linked and loaded
+ * device drivers. The interface must be registered before a signalling
+ * manager can be attached.
+ *
+ * Arguments:
+ * cup pointer to interface's common unit structure
+ * name pointer to device name string
+ * sdp pointer to interface's stack services
+ *
+ * Returns:
+ * 0 registration successful
+ * errno registration failed - reason indicated
+ *
+ */
+int
+atm_physif_register(cup, name, sdp)
+ Cmn_unit *cup;
+ char *name;
+ struct stack_defn *sdp;
+{
+ struct atm_pif *pip;
+ int s;
+
+ /*
+ * See if we need to be initialized
+ */
+ if (!atm_init)
+ atm_initialize();
+
+ /*
+ * Make sure we're not already registered
+ */
+ if (cup->cu_flags & CUF_REGISTER) {
+ return (EALREADY);
+ }
+
+ s = splnet();
+
+ /*
+ * Make sure an interface is only registered once
+ */
+ for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) {
+ if ((cup->cu_unit == pip->pif_unit) &&
+ (strcmp(name, pip->pif_name) == 0)) {
+ (void) splx(s);
+ return (EEXIST);
+ }
+ }
+
+ /*
+ * Fill in physical interface parameters
+ */
+ pip = &cup->cu_pif;
+ pip->pif_name = name;
+ pip->pif_unit = cup->cu_unit;
+ pip->pif_flags = PIF_UP;
+ pip->pif_services = sdp;
+ pip->pif_ioctl = atm_physif_ioctl;
+
+ /*
+ * Link in the interface and mark us registered
+ */
+ LINK2TAIL(pip, struct atm_pif, atm_interface_head, pif_next);
+ cup->cu_flags |= CUF_REGISTER;
+
+ (void) splx(s);
+ return (0);
+}
+
+
+/*
+ * De-register an ATM physical interface
+ *
+ * Each ATM interface must de-register itself before downing the interface.
+ * The interface's signalling manager will be detached and any network
+ * interface and VCC control blocks will be freed.
+ *
+ * Arguments:
+ * cup pointer to interface's common unit structure
+ *
+ * Returns:
+ * 0 de-registration successful
+ * errno de-registration failed - reason indicated
+ *
+ */
+int
+atm_physif_deregister(cup)
+ Cmn_unit *cup;
+{
+ struct atm_pif *pip = (struct atm_pif *)&cup->cu_pif;
+ Cmn_vcc *cvp;
+ int err;
+ int s = splnet();
+
+ /*
+ * Detach and deregister, if needed
+ */
+ if ((cup->cu_flags & CUF_REGISTER)) {
+
+ /*
+ * Detach from signalling manager
+ */
+ if (pip->pif_sigmgr != NULL) {
+ err = atm_sigmgr_detach(pip);
+ if (err && (err != ENOENT)) {
+ (void) splx(s);
+ return (err);
+ }
+ }
+
+ /*
+ * Make sure signalling manager is detached
+ */
+ if (pip->pif_sigmgr != NULL) {
+ (void) splx(s);
+ return (EBUSY);
+ }
+
+ /*
+ * Unlink interface
+ */
+ UNLINK(pip, struct atm_pif, atm_interface_head, pif_next);
+
+ cup->cu_flags &= ~CUF_REGISTER;
+ }
+
+ /*
+ * Free all of our network interfaces
+ */
+ atm_physif_freenifs(pip);
+
+ /*
+ * Free unit's vcc information
+ */
+ cvp = cup->cu_vcc;
+ while (cvp) {
+ atm_free(cvp);
+ cvp = cvp->cv_next;
+ }
+ cup->cu_vcc = (Cmn_vcc *)NULL;
+
+ (void) splx(s);
+
+ return (0);
+}
+
+
+/*
+ * Free all network interfaces on a physical interface
+ *
+ * Arguments
+ * pip pointer to physical interface structure
+ *
+ * Returns
+ * none
+ *
+ */
+void
+atm_physif_freenifs(pip)
+ struct atm_pif *pip;
+{
+ struct atm_nif *nip = pip->pif_nif;
+ int s = splnet();
+
+ while ( nip )
+ {
+ /*
+ * atm_nif_detach zeros pointers - save so we can
+ * walk the chain.
+ */
+ struct atm_nif *nipp = nip->nif_pnext;
+
+ /*
+ * Clean up network i/f trails
+ */
+ atm_nif_detach ( nip );
+ atm_free ((caddr_t)nip);
+ nip = nipp;
+ }
+ pip->pif_nif = (struct atm_nif *)NULL;
+
+ (void) splx(s);
+
+ return;
+}
+
+
+/*
+ * Handle physical interface ioctl's
+ *
+ * See <netatm/atm_ioctl.h> for definitions.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * code Ioctl function (sub)code
+ * data Data block. On input contains command,
+ * on output, contains results
+ * arg Optional code specific arguments
+ *
+ * Returns:
+ * 0 Request processed successfully
+ * errno Request failed - reason code
+ *
+ */
+static int
+atm_physif_ioctl(code, data, arg)
+ int code;
+ caddr_t data;
+ caddr_t arg;
+{
+ struct atminfreq *aip = (struct atminfreq *)data;
+ struct atmsetreq *asr = (struct atmsetreq *)data;
+ struct atm_pif *pip;
+ struct atm_nif *nip;
+ struct sigmgr *smp;
+ struct siginst *sip;
+ struct ifnet *ifp;
+ Cmn_unit *cup;
+ Atm_config *acp;
+ caddr_t buf = aip->air_buf_addr;
+ struct air_phy_stat_rsp *apsp;
+ struct air_int_rsp apr;
+ struct air_netif_rsp anr;
+ struct air_cfg_rsp acr;
+ int count, len, buf_len = aip->air_buf_len;
+ int err = 0;
+ char ifname[2*IFNAMSIZ];
+#if (defined(BSD) && (BSD >= 199103))
+ struct ifaddr *ifa;
+ struct in_ifaddr *ia;
+ struct sockaddr_dl *sdl;
+#endif
+
+
+ switch ( aip->air_opcode ) {
+
+ case AIOCS_INF_INT:
+ /*
+ * Get physical interface information
+ */
+ aip = (struct atminfreq *)data;
+ pip = (struct atm_pif *)arg;
+
+ /*
+ * Make sure there's room in user buffer
+ */
+ if (aip->air_buf_len < sizeof(apr)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill in info to be returned
+ */
+ KM_ZERO((caddr_t)&apr, sizeof(apr));
+ smp = pip->pif_sigmgr;
+ sip = pip->pif_siginst;
+ (void) sprintf(apr.anp_intf, "%s%d", pip->pif_name,
+ pip->pif_unit );
+ if ( pip->pif_nif )
+ {
+ strcpy(apr.anp_nif_pref, pip->pif_nif->nif_if.if_name);
+
+ nip = pip->pif_nif;
+ while ( nip ) {
+ apr.anp_nif_cnt++;
+ nip = nip->nif_pnext;
+ }
+ }
+ if (sip) {
+ ATM_ADDR_COPY(&sip->si_addr, &apr.anp_addr);
+ ATM_ADDR_COPY(&sip->si_subaddr, &apr.anp_subaddr);
+ apr.anp_sig_proto = smp->sm_proto;
+ apr.anp_sig_state = sip->si_state;
+ }
+
+ /*
+ * Copy data to user buffer
+ */
+ err = copyout((caddr_t)&apr, aip->air_buf_addr, sizeof(apr));
+ if (err)
+ break;
+
+ /*
+ * Update buffer pointer/count
+ */
+ aip->air_buf_addr += sizeof(apr);
+ aip->air_buf_len -= sizeof(apr);
+ break;
+
+ case AIOCS_INF_NIF:
+ /*
+ * Get network interface information
+ */
+ aip = (struct atminfreq *)data;
+ nip = (struct atm_nif *)arg;
+ ifp = &nip->nif_if;
+ pip = nip->nif_pif;
+
+ /*
+ * Make sure there's room in user buffer
+ */
+ if (aip->air_buf_len < sizeof(anr)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill in info to be returned
+ */
+ KM_ZERO((caddr_t)&anr, sizeof(anr));
+ (void) sprintf(anr.anp_intf, "%s%d", ifp->if_name,
+ ifp->if_unit);
+ IFP_TO_IA(ifp, ia);
+ if (ia) {
+ anr.anp_proto_addr = *ia->ia_ifa.ifa_addr;
+ }
+ (void) sprintf(anr.anp_phy_intf, "%s%d", pip->pif_name,
+ pip->pif_unit);
+
+ /*
+ * Copy data to user buffer
+ */
+ err = copyout((caddr_t)&anr, aip->air_buf_addr, sizeof(anr));
+ if (err)
+ break;
+
+ /*
+ * Update buffer pointer/count
+ */
+ aip->air_buf_addr += sizeof(anr);
+ aip->air_buf_len -= sizeof(anr);
+ break;
+
+ case AIOCS_INF_PIS:
+ /*
+ * Get per interface statistics
+ */
+ pip = (struct atm_pif *)arg;
+ if ( pip == NULL )
+ return ( ENXIO );
+ sprintf ( ifname, "%s%d", pip->pif_name, pip->pif_unit );
+
+ /*
+ * Cast response into users buffer
+ */
+ apsp = (struct air_phy_stat_rsp *)buf;
+
+ /*
+ * Sanity check
+ */
+ len = sizeof ( struct air_phy_stat_rsp );
+ if ( buf_len < len )
+ return ( ENOSPC );
+
+ /*
+ * Copy interface name into response
+ */
+ if ( err = copyout ( ifname, apsp->app_intf, IFNAMSIZ ) )
+ break;
+
+ /*
+ * Copy counters
+ */
+ if ( err = copyout ( &pip->pif_ipdus, &apsp->app_ipdus,
+ len - sizeof ( apsp->app_intf ) ) )
+ break;
+
+ /*
+ * Adjust buffer elements
+ */
+ buf += len;
+ buf_len -= len;
+
+ aip->air_buf_addr = buf;
+ aip->air_buf_len = buf_len;
+ break;
+
+ case AIOCS_SET_NIF:
+ /*
+ * Set NIF - allow user to configure 1 or more logical
+ * interfaces per physical interface.
+ */
+
+ /*
+ * Get pointer to physical interface structure from
+ * ioctl argument.
+ */
+ pip = (struct atm_pif *)arg;
+ cup = (Cmn_unit *)pip;
+
+ /*
+ * Sanity check - are we already connected to something?
+ */
+ if ( pip->pif_sigmgr )
+ {
+ err = EBUSY;
+ break;
+ }
+
+ /*
+ * Free any previously allocated NIFs
+ */
+ atm_physif_freenifs(pip);
+
+ /*
+ * Add list of interfaces
+ */
+ for ( count = 0; count < asr->asr_nif_cnt; count++ )
+ {
+ nip = (struct atm_nif *)atm_allocate(cup->cu_nif_pool);
+ if ( nip == NULL )
+ {
+ /*
+ * Destroy any successful nifs
+ */
+ atm_physif_freenifs(pip);
+ err = ENOMEM;
+ break;
+ }
+
+ nip->nif_pif = pip;
+ ifp = &nip->nif_if;
+
+ strcpy ( nip->nif_name, asr->asr_nif_pref );
+ nip->nif_sel = count;
+
+ ifp->if_name = nip->nif_name;
+ ifp->if_unit = count;
+ ifp->if_mtu = ATM_NIF_MTU;
+ ifp->if_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
+ ifp->if_output = atm_ifoutput;
+ ifp->if_ioctl = atm_if_ioctl;
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+#if (defined(BSD) && (BSD >= 199103))
+ /*
+ * Set if_type and if_baudrate
+ */
+ ifp->if_type = IFT_ATM;
+ switch ( cup->cu_config.ac_media ) {
+ case MEDIA_TAXI_100:
+ ifp->if_baudrate = 100000000;
+ break;
+ case MEDIA_TAXI_140:
+ ifp->if_baudrate = 140000000;
+ break;
+ case MEDIA_OC3C:
+ case MEDIA_OC12C:
+ case MEDIA_UTP155:
+ ifp->if_baudrate = 155000000;
+ break;
+ }
+#endif
+
+ if ( err = atm_nif_attach ( nip ) )
+ {
+ atm_free ( (caddr_t)nip );
+
+ /*
+ * Destroy any successful nifs
+ */
+ atm_physif_freenifs(pip);
+ break;
+ }
+#if (defined(BSD) && (BSD >= 199103))
+ /*
+ * Set macaddr in <Link> address
+ */
+ ifp->if_addrlen = 6;
+ ifa = ifnet_addrs[ifp->if_index - 1];
+ if ( ifa ) {
+ sdl = (struct sockaddr_dl *)
+ ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ifp->if_addrlen;
+ bcopy ( (caddr_t)&cup->cu_config.ac_macaddr,
+ LLADDR(sdl), ifp->if_addrlen );
+ }
+#endif
+ }
+ break;
+
+ case AIOCS_INF_CFG:
+ /*
+ * Get adapter configuration information
+ */
+ aip = (struct atminfreq *)data;
+ pip = (struct atm_pif *)arg;
+ cup = (Cmn_unit *)pip;
+ acp = &cup->cu_config;
+
+ /*
+ * Make sure there's room in user buffer
+ */
+ if (aip->air_buf_len < sizeof(acr)) {
+ err = ENOSPC;
+ break;
+ }
+
+ /*
+ * Fill in info to be returned
+ */
+ KM_ZERO((caddr_t)&acr, sizeof(acr));
+ (void) sprintf(acr.acp_intf, "%s%d", pip->pif_name,
+ pip->pif_unit);
+ KM_COPY((caddr_t)acp, (caddr_t)&acr.acp_cfg,
+ sizeof(Atm_config));
+
+ /*
+ * Copy data to user buffer
+ */
+ err = copyout((caddr_t)&acr, aip->air_buf_addr,
+ sizeof(acr));
+ if (err)
+ break;
+
+ /*
+ * Update buffer pointer/count
+ */
+ aip->air_buf_addr += sizeof(acr);
+ aip->air_buf_len -= sizeof(acr);
+ break;
+
+ case AIOCS_INF_VST:
+ /*
+ * Pass off to device-specific handler
+ */
+ cup = (Cmn_unit *)arg;
+ if (cup == NULL)
+ err = ENXIO;
+ else
+ err = (*cup->cu_ioctl)(code, data, arg);
+ break;
+
+ default:
+ err = ENOSYS;
+ }
+
+ return ( err );
+}
+
+
+/*
+ * Register a Network Convergence Module
+ *
+ * Each ATM network convergence module must register itself here before
+ * it will receive network interface status notifications.
+ *
+ * Arguments:
+ * ncp pointer to network convergence definition structure
+ *
+ * Returns:
+ * 0 registration successful
+ * errno registration failed - reason indicated
+ *
+ */
+int
+atm_netconv_register(ncp)
+ struct atm_ncm *ncp;
+{
+ struct atm_ncm *tdp;
+ int s = splnet();
+
+ /*
+ * See if we need to be initialized
+ */
+ if (!atm_init)
+ atm_initialize();
+
+ /*
+ * Validate protocol family
+ */
+ if (ncp->ncm_family > AF_MAX) {
+ (void) splx(s);
+ return (EINVAL);
+ }
+
+ /*
+ * Ensure no duplicates
+ */
+ for (tdp = atm_netconv_head; tdp != NULL; tdp = tdp->ncm_next) {
+ if (tdp->ncm_family == ncp->ncm_family) {
+ (void) splx(s);
+ return (EEXIST);
+ }
+ }
+
+ /*
+ * Add module to list
+ */
+ LINK2TAIL(ncp, struct atm_ncm, atm_netconv_head, ncm_next);
+
+ /*
+ * Add new interface output function
+ */
+ atm_ifouttbl[ncp->ncm_family] = ncp->ncm_ifoutput;
+
+ (void) splx(s);
+ return (0);
+}
+
+
+/*
+ * De-register an ATM Network Convergence Module
+ *
+ * Each ATM network convergence provider must de-register its registered
+ * service(s) before terminating. Specifically, loaded kernel modules
+ * must de-register their services before unloading themselves.
+ *
+ * Arguments:
+ * ncp pointer to network convergence definition structure
+ *
+ * Returns:
+ * 0 de-registration successful
+ * errno de-registration failed - reason indicated
+ *
+ */
+int
+atm_netconv_deregister(ncp)
+ struct atm_ncm *ncp;
+{
+ int found, s = splnet();
+
+ /*
+ * Remove module from list
+ */
+ UNLINKF(ncp, struct atm_ncm, atm_netconv_head, ncm_next, found);
+
+ if (!found) {
+ (void) splx(s);
+ return (ENOENT);
+ }
+
+ /*
+ * Remove module's interface output function
+ */
+ atm_ifouttbl[ncp->ncm_family] = NULL;
+
+ (void) splx(s);
+ return (0);
+}
+
+
+/*
+ * Attach an ATM Network Interface
+ *
+ * Before an ATM network interface can be used by the system, the owning
+ * device interface must attach the network interface using this function.
+ * The physical interface for this network interface must have been previously
+ * registered (using atm_interface_register). The network interface will be
+ * added to the kernel's interface list and to the physical interface's list.
+ * The caller is responsible for initializing the control block fields.
+ *
+ * Arguments:
+ * nip pointer to atm network interface control block
+ *
+ * Returns:
+ * 0 attach successful
+ * errno attach failed - reason indicated
+ *
+ */
+int
+atm_nif_attach(nip)
+ struct atm_nif *nip;
+{
+ struct atm_pif *pip, *pip2;
+ struct ifnet *ifp;
+ struct atm_ncm *ncp;
+ int s;
+
+ ifp = &nip->nif_if;
+ pip = nip->nif_pif;
+
+ s = splimp();
+
+ /*
+ * Verify physical interface is registered
+ */
+ for (pip2 = atm_interface_head; pip2 != NULL; pip2 = pip2->pif_next) {
+ if (pip == pip2)
+ break;
+ }
+ if ((pip == NULL) || (pip2 == NULL)) {
+ (void) splx(s);
+ return (EFAULT);
+ }
+
+ /*
+ * Add to system interface list
+ */
+ if_attach(ifp);
+
+ /*
+ * Add to physical interface list
+ */
+ LINK2TAIL(nip, struct atm_nif, pip->pif_nif, nif_pnext);
+
+ /*
+ * Notify network convergence modules of new network i/f
+ */
+ for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
+ int err;
+
+ err = (*ncp->ncm_stat)(NCM_ATTACH, nip, 0);
+ if (err) {
+ atm_nif_detach(nip);
+ (void) splx(s);
+ return (err);
+ }
+ }
+
+ (void) splx(s);
+ return (0);
+}
+
+
+/*
+ * Detach an ATM Network Interface
+ *
+ * Before an ATM network interface control block can be freed, all kernel
+ * references to/from this block must be released. This function will delete
+ * all routing references to the interface and free all interface addresses
+ * for the interface. The network interface will then be removed from the
+ * kernel's interface list and from the owning physical interface's list.
+ * The caller is responsible for free'ing the control block.
+ *
+ * Arguments:
+ * nip pointer to atm network interface control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+atm_nif_detach(nip)
+ struct atm_nif *nip;
+{
+ struct atm_ncm *ncp;
+ int s, i;
+ struct ifnet *ifp = &nip->nif_if;
+ struct ifaddr *ifa;
+ struct in_ifaddr *ia;
+ struct radix_node_head *rnh;
+
+
+ s = splimp();
+
+ /*
+ * Notify convergence modules of network i/f demise
+ */
+ for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
+ (void) (*ncp->ncm_stat)(NCM_DETACH, nip, 0);
+ }
+
+ /*
+ * Mark interface down
+ */
+ if_down(ifp);
+
+ /*
+ * Free all interface routes and addresses
+ */
+ while (1) {
+ IFP_TO_IA(ifp, ia);
+ if (ia == NULL)
+ break;
+
+ /* Delete interface route */
+ in_ifscrub(ifp, ia);
+
+ /* Remove interface address from queues */
+ ifa = &ia->ia_ifa;
+ TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
+ TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
+
+ /* Free interface address */
+ IFAFREE(ifa);
+ }
+
+ /*
+ * Delete all remaining routes using this interface
+ * Unfortuneatly the only way to do this is to slog through
+ * the entire routing table looking for routes which point
+ * to this interface...oh well...
+ */
+ for (i = 1; i <= AF_MAX; i++) {
+ if ((rnh = rt_tables[i]) == NULL)
+ continue;
+ (void) rnh->rnh_walktree(rnh, atm_netif_rtdel, ifp);
+ }
+
+ /*
+ * Remove from system interface list (ie. if_detach())
+ */
+ TAILQ_REMOVE(&ifnet, ifp, if_link);
+
+ /*
+ * Remove from physical interface list
+ */
+ UNLINK(nip, struct atm_nif, nip->nif_pif->pif_nif, nif_pnext);
+
+ (void) splx(s);
+}
+
+
+/*
+ * Delete Routes for a Network Interface
+ *
+ * Called for each routing entry via the rnh->rnh_walktree() call above
+ * to delete all route entries referencing a detaching network interface.
+ *
+ * Arguments:
+ * rn pointer to node in the routing table
+ * arg argument passed to rnh->rnh_walktree() - detaching interface
+ *
+ * Returns:
+ * 0 successful
+ * errno failed - reason indicated
+ *
+ */
+static int
+atm_netif_rtdel(rn, arg)
+ struct radix_node *rn;
+ void *arg;
+{
+ struct rtentry *rt = (struct rtentry *)rn;
+ struct ifnet *ifp = arg;
+ int err;
+
+ if (rt->rt_ifp == ifp) {
+
+ /*
+ * Protect (sorta) against walktree recursion problems
+ * with cloned routes
+ */
+ if ((rt->rt_flags & RTF_UP) == 0)
+ return (0);
+
+ err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
+ rt_mask(rt), rt->rt_flags,
+ (struct rtentry **) NULL);
+ if (err) {
+ log(LOG_WARNING, "atm_netif_rtdel: error %d\n", err);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * Set an ATM Network Interface address
+ *
+ * This is called from a device interface when processing an SIOCSIFADDR
+ * ioctl request. We just notify all convergence modules of the new address
+ * and hope everyone has non-overlapping interests, since if someone reports
+ * an error we don't go back and tell everyone to undo the change.
+ *
+ * Arguments:
+ * nip pointer to atm network interface control block
+ * ifa pointer to new interface address
+ *
+ * Returns:
+ * 0 set successful
+ * errno set failed - reason indicated
+ *
+ */
+int
+atm_nif_setaddr(nip, ifa)
+ struct atm_nif *nip;
+ struct ifaddr *ifa;
+{
+ struct atm_ncm *ncp;
+ int err = 0, s = splnet();
+
+ /*
+ * Notify convergence modules of network i/f change
+ */
+ for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) {
+ err = (*ncp->ncm_stat)(NCM_SETADDR, nip, (int)ifa);
+ if (err)
+ break;
+ }
+ (void) splx(s);
+
+ return (err);
+}
+
+
+/*
+ * ATM Interface Packet Output
+ *
+ * All ATM network interfaces must have their ifnet if_output address set to
+ * this function. Since no existing network layer code is to be modified
+ * for ATM support, this function serves as the hook to allow network output
+ * packets to be assigned to their proper outbound VCC. Each network address
+ * family which is to be supported over ATM must be assigned an output
+ * packet processing function via atm_netconv_register().
+ *
+ * Arguments:
+ * ifp pointer to ifnet structure
+ * m pointer to packet buffer chain to be output
+ * dst pointer to packet's network destination address
+ *
+ * Returns:
+ * 0 packet queued to interface
+ * errno output failed - reason indicated
+ *
+ */
+int
+#if (defined(BSD) && (BSD >= 199103))
+atm_ifoutput(ifp, m, dst, rt)
+#else
+atm_ifoutput(ifp, m, dst)
+#endif
+ struct ifnet *ifp;
+ KBuffer *m;
+ struct sockaddr *dst;
+#if (defined(BSD) && (BSD >= 199103))
+ struct rtentry *rt;
+#endif
+{
+ u_short fam = dst->sa_family;
+ int (*func)__P((struct ifnet *, KBuffer *,
+ struct sockaddr *));
+
+ /*
+ * Validate address family
+ */
+ if (fam > AF_MAX) {
+ KB_FREEALL(m);
+ return (EAFNOSUPPORT);
+ }
+
+ /*
+ * Hand packet off for dst-to-VCC mapping
+ */
+ func = atm_ifouttbl[fam];
+ if (func == NULL) {
+ KB_FREEALL(m);
+ return (EAFNOSUPPORT);
+ }
+ return ((*func)(ifp, m, dst));
+}
+
+
+/*
+ * Handle interface ioctl requests.
+ *
+ * Arguments:
+ * ifp pointer to network interface structure
+ * cmd IOCTL cmd
+ * data arguments to/from ioctl
+ *
+ * Returns:
+ * error errno value
+ */
+static int
+atm_if_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ register struct ifreq *ifr = (struct ifreq *)data;
+ struct atm_nif *nip = (struct atm_nif *)ifp;
+ int error = 0;
+ int s = splnet();
+
+ switch ( cmd )
+ {
+ case SIOCGIFADDR:
+ KM_COPY ( (caddr_t)&(nip->nif_pif->pif_macaddr),
+ (caddr_t)ifr->ifr_addr.sa_data,
+ sizeof(struct mac_addr) );
+ break;
+
+ case SIOCSIFADDR:
+ error = atm_nif_setaddr ( nip, (struct ifaddr *)data);
+ ifp->if_flags |= IFF_UP | IFF_RUNNING | IFF_BROADCAST;
+ break;
+
+ case SIOCGIFFLAGS:
+ *(short *)data = ifp->if_flags;
+ break;
+
+ case SIOCSIFFLAGS:
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ (void) splx(s);
+ return ( error );
+}
+
+
+/*
+ * Parse interface name
+ *
+ * Parses an interface name string into a name and a unit component.
+ *
+ * Arguments:
+ * name pointer to interface name string
+ * namep address to store interface name
+ * size size available at namep
+ * unitp address to store interface unit number
+ *
+ * Returns:
+ * 0 name parsed
+ * else parse error
+ *
+ */
+static int
+atm_ifparse(name, namep, size, unitp)
+ char *name;
+ char *namep;
+ int size;
+ int *unitp;
+{
+ char *cp, *np;
+ int len = 0, unit = 0;
+
+ /*
+ * Separate supplied string into name and unit parts.
+ */
+ cp = name;
+ np = namep;
+ while (*cp) {
+ if (*cp >= '0' && *cp <= '9')
+ break;
+ if (++len >= size)
+ return (-1);
+ *np++ = *cp++;
+ }
+ *np = '\0';
+ while (*cp && *cp >= '0' && *cp <= '9')
+ unit = 10 * unit + *cp++ - '0';
+
+ *unitp = unit;
+
+ return (0);
+}
+
+
+/*
+ * Locate ATM physical interface via name
+ *
+ * Uses the supplied interface name string to locate a registered
+ * ATM physical interface.
+ *
+ * Arguments:
+ * name pointer to interface name string
+ *
+ * Returns:
+ * 0 interface not found
+ * else pointer to atm physical interface structure
+ *
+ */
+struct atm_pif *
+atm_pifname(name)
+ char *name;
+{
+ struct atm_pif *pip;
+ char n[IFNAMSIZ];
+ int unit;
+
+ /*
+ * Break down name
+ */
+ if (atm_ifparse(name, n, sizeof(n), &unit))
+ return ((struct atm_pif *)0);
+
+ /*
+ * Look for the physical interface
+ */
+ for (pip = atm_interface_head; pip; pip = pip->pif_next) {
+ if ((pip->pif_unit == unit) && (strcmp(pip->pif_name, n) == 0))
+ break;
+ }
+
+ return (pip);
+}
+
+
+/*
+ * Locate ATM network interface via name
+ *
+ * Uses the supplied interface name string to locate an ATM network interface.
+ *
+ * Arguments:
+ * name pointer to interface name string
+ *
+ * Returns:
+ * 0 interface not found
+ * else pointer to atm network interface structure
+ *
+ */
+struct atm_nif *
+atm_nifname(name)
+ char *name;
+{
+ struct atm_pif *pip;
+ struct atm_nif *nip;
+ char n[IFNAMSIZ];
+ int unit;
+
+ /*
+ * Break down name
+ */
+ if (atm_ifparse(name, n, sizeof(n), &unit))
+ return ((struct atm_nif *)0);
+
+ /*
+ * Search thru each physical interface
+ */
+ for (pip = atm_interface_head; pip; pip = pip->pif_next) {
+ /*
+ * Looking for network interface
+ */
+ for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
+ struct ifnet *ifp = (struct ifnet *)nip;
+ if ((ifp->if_unit == unit) &&
+ (strcmp(ifp->if_name, n) == 0))
+ return (nip);
+ }
+ }
+ return (NULL);
+}
+
OpenPOWER on IntegriCloud