diff options
author | Jennifer Averett <jennifer.averett@oarcorp.com> | 2012-09-06 09:17:47 -0500 |
---|---|---|
committer | Jennifer Averett <jennifer.averett@oarcorp.com> | 2012-09-06 09:17:47 -0500 |
commit | 6d7f48849e4688d614fdbdee2eb399d527658a2c (patch) | |
tree | d2960c1e618621746049b4c2f855b2caa91400bb | |
parent | freebsd-to-rtems.py: Removed cdefs.h, signal.h, and signalvar.h (diff) | |
download | rtems-libbsd-6d7f48849e4688d614fdbdee2eb399d527658a2c.tar.bz2 |
Added netatalk files
This is part of a larger patch where network command structure is being
ported. It was easier to move these files in than to carve it out of
the command code.
-rw-r--r-- | Makefile | 10 | ||||
-rwxr-xr-x | freebsd-to-rtems.py | 17 | ||||
-rw-r--r-- | freebsd/netatalk/aarp.c | 726 | ||||
-rw-r--r-- | freebsd/netatalk/aarp.h | 86 | ||||
-rw-r--r-- | freebsd/netatalk/at.h | 86 | ||||
-rw-r--r-- | freebsd/netatalk/at_control.c | 888 | ||||
-rw-r--r-- | freebsd/netatalk/at_extern.h | 67 | ||||
-rw-r--r-- | freebsd/netatalk/at_proto.c | 66 | ||||
-rw-r--r-- | freebsd/netatalk/at_rmx.c | 119 | ||||
-rw-r--r-- | freebsd/netatalk/at_var.h | 77 | ||||
-rw-r--r-- | freebsd/netatalk/ddp.h | 137 | ||||
-rw-r--r-- | freebsd/netatalk/ddp_input.c | 442 | ||||
-rw-r--r-- | freebsd/netatalk/ddp_output.c | 249 | ||||
-rw-r--r-- | freebsd/netatalk/ddp_pcb.c | 418 | ||||
-rw-r--r-- | freebsd/netatalk/ddp_pcb.h | 84 | ||||
-rw-r--r-- | freebsd/netatalk/ddp_usrreq.c | 333 | ||||
-rw-r--r-- | freebsd/netatalk/ddp_var.h | 63 | ||||
-rw-r--r-- | freebsd/netatalk/endian.h | 31 | ||||
-rw-r--r-- | freebsd/netatalk/phase2.h | 34 |
19 files changed, 3932 insertions, 1 deletions
@@ -397,6 +397,14 @@ C_FILES += freebsd/kern/subr_bufring.c C_FILES += freebsd/dev/led/led.c C_FILES += freebsd/kern/subr_unit.c C_FILES += freebsd/dev/pci/pci_pci.c +C_FILES += freebsd/netatalk/aarp.c +C_FILES += freebsd/netatalk/at_control.c +C_FILES += freebsd/netatalk/at_rmx.c +C_FILES += freebsd/netatalk/ddp_input.c +C_FILES += freebsd/netatalk/ddp_pcb.c +C_FILES += freebsd/netatalk/ddp_usrreq.c +C_FILES += freebsd/netatalk/at_proto.c +C_FILES += freebsd/netatalk/ddp_output.c ifeq ($(RTEMS_CPU), i386) C_FILES += freebsd/i386/pci/pci_bus.c C_FILES += freebsd/i386/i386/legacy.c @@ -1002,7 +1010,7 @@ install_bsd: $(LIB) install -c -m 644 $(LIB) $(INSTALL_BASE) cd rtemsbsd; for i in `find freebsd -name '*.h'` ; do \ install -c -m 644 -D "$$i" "$(INSTALL_BASE)/include/$$i" ; done - cd contrib/altq ; for i in `find freebsd -name '*.h'` ; do \ + cd contrib/altq; for i in `find freebsd -name '*.h'` ; do \ install -c -m 644 -D "$$i" "$(INSTALL_BASE)/include/$$i" ; done for i in `find freebsd -name '*.h' | $(CPU_SED)` ; do \ install -c -m 644 -D "$$i" "$(INSTALL_BASE)/include/$$i" ; done diff --git a/freebsd-to-rtems.py b/freebsd-to-rtems.py index daf24d11..d4fe50bd 100755 --- a/freebsd-to-rtems.py +++ b/freebsd-to-rtems.py @@ -1334,6 +1334,15 @@ devNic.addHeaderFiles( 'dev/pci/pcib_private.h', 'isa/isavar.h', 'isa/pnpvar.h', + 'netatalk/at.h', + 'netatalk/endian.h', + 'netatalk/aarp.h', + 'netatalk/at_extern.h', + 'netatalk/at_var.h', + 'netatalk/ddp.h', + 'netatalk/ddp_pcb.h', + 'netatalk/ddp_var.h', + 'netatalk/phase2.h', ] ) @@ -1392,6 +1401,14 @@ devNic.addSourceFiles( 'dev/led/led.c', 'kern/subr_unit.c', 'dev/pci/pci_pci.c', + 'netatalk/aarp.c', + 'netatalk/at_control.c', + 'netatalk/at_rmx.c', + 'netatalk/ddp_input.c', + 'netatalk/ddp_pcb.c', + 'netatalk/ddp_usrreq.c', + 'netatalk/at_proto.c', + 'netatalk/ddp_output.c', ] ) diff --git a/freebsd/netatalk/aarp.c b/freebsd/netatalk/aarp.c new file mode 100644 index 00000000..63fabede --- /dev/null +++ b/freebsd/netatalk/aarp.c @@ -0,0 +1,726 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Copyright (c) 2004-2009 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1990,1991,1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ + */ + +#include <freebsd/local/opt_atalk.h> + +#include <freebsd/sys/param.h> +#include <freebsd/sys/systm.h> +#include <freebsd/sys/mbuf.h> +#include <freebsd/sys/kernel.h> +#include <freebsd/sys/socket.h> +#include <freebsd/sys/syslog.h> + +#include <freebsd/net/if.h> +#include <freebsd/net/if_dl.h> + +#include <freebsd/netinet/in.h> +#undef s_net +#include <freebsd/netinet/if_ether.h> + +#include <freebsd/netatalk/at.h> +#include <freebsd/netatalk/at_var.h> +#include <freebsd/netatalk/aarp.h> +#include <freebsd/netatalk/phase2.h> +#include <freebsd/netatalk/at_extern.h> + +#include <freebsd/security/mac/mac_framework.h> + +static void aarptfree(struct aarptab *aat); +static void at_aarpinput(struct ifnet *ifp, struct mbuf *m); + +#define AARPTAB_BSIZ 9 +#define AARPTAB_NB 19 +#define AARPTAB_SIZE (AARPTAB_BSIZ * AARPTAB_NB) +static struct aarptab aarptab[AARPTAB_SIZE]; + +struct mtx aarptab_mtx; +MTX_SYSINIT(aarptab_mtx, &aarptab_mtx, "aarptab_mtx", MTX_DEF); + +#define AARPTAB_HASH(a) ((((a).s_net << 8) + (a).s_node) % AARPTAB_NB) + +#define AARPTAB_LOOK(aat, addr) do { \ + int n; \ + \ + AARPTAB_LOCK_ASSERT(); \ + aat = &aarptab[ AARPTAB_HASH(addr) * AARPTAB_BSIZ ]; \ + for (n = 0; n < AARPTAB_BSIZ; n++, aat++) { \ + if (aat->aat_ataddr.s_net == (addr).s_net && \ + aat->aat_ataddr.s_node == (addr).s_node) \ + break; \ + } \ + if (n >= AARPTAB_BSIZ) \ + aat = NULL; \ +} while (0) + +#define AARPT_AGE (60 * 1) +#define AARPT_KILLC 20 +#define AARPT_KILLI 3 + +static const u_char atmulticastaddr[6] = { + 0x09, 0x00, 0x07, 0xff, 0xff, 0xff, +}; + +u_char at_org_code[3] = { + 0x08, 0x00, 0x07, +}; +const u_char aarp_org_code[3] = { + 0x00, 0x00, 0x00, +}; + +static struct callout_handle aarptimer_ch = + CALLOUT_HANDLE_INITIALIZER(&aarptimer_ch); + +static void +aarptimer(void *ignored) +{ + struct aarptab *aat; + int i; + + aarptimer_ch = timeout(aarptimer, NULL, AARPT_AGE * hz); + aat = aarptab; + AARPTAB_LOCK(); + for (i = 0; i < AARPTAB_SIZE; i++, aat++) { + if (aat->aat_flags == 0 || (aat->aat_flags & ATF_PERM)) + continue; + if (++aat->aat_timer < ((aat->aat_flags & ATF_COM) ? + AARPT_KILLC : AARPT_KILLI)) + continue; + aarptfree(aat); + } + AARPTAB_UNLOCK(); +} + +/* + * Search through the network addresses to find one that includes the given + * network. Remember to take netranges into consideration. + * + * The _locked variant relies on the caller holding the at_ifaddr lock; the + * unlocked variant returns a reference that the caller must dispose of. + */ +struct at_ifaddr * +at_ifawithnet_locked(struct sockaddr_at *sat) +{ + struct at_ifaddr *aa; + struct sockaddr_at *sat2; + + AT_IFADDR_LOCK_ASSERT(); + + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + sat2 = &(aa->aa_addr); + if (sat2->sat_addr.s_net == sat->sat_addr.s_net) + break; + if ((aa->aa_flags & AFA_PHASE2) && + (ntohs(aa->aa_firstnet) <= ntohs(sat->sat_addr.s_net)) && + (ntohs(aa->aa_lastnet) >= ntohs(sat->sat_addr.s_net))) + break; + } + return (aa); +} + +struct at_ifaddr * +at_ifawithnet(struct sockaddr_at *sat) +{ + struct at_ifaddr *aa; + + AT_IFADDR_RLOCK(); + aa = at_ifawithnet_locked(sat); + if (aa != NULL) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + return (aa); +} + +static void +aarpwhohas(struct ifnet *ifp, struct sockaddr_at *sat) +{ + struct mbuf *m; + struct ether_header *eh; + struct ether_aarp *ea; + struct at_ifaddr *aa; + struct llc *llc; + struct sockaddr sa; + + AARPTAB_UNLOCK_ASSERT(); + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m == NULL) + return; +#ifdef MAC + mac_netatalk_aarp_send(ifp, m); +#endif + m->m_len = sizeof(*ea); + m->m_pkthdr.len = sizeof(*ea); + MH_ALIGN(m, sizeof(*ea)); + + ea = mtod(m, struct ether_aarp *); + bzero((caddr_t)ea, sizeof(*ea)); + + ea->aarp_hrd = htons(AARPHRD_ETHER); + ea->aarp_pro = htons(ETHERTYPE_AT); + ea->aarp_hln = sizeof(ea->aarp_sha); + ea->aarp_pln = sizeof(ea->aarp_spu); + ea->aarp_op = htons(AARPOP_REQUEST); + bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha, sizeof(ea->aarp_sha)); + + /* + * We need to check whether the output ethernet type should be phase + * 1 or 2. We have the interface that we'll be sending the aarp out. + * We need to find an AppleTalk network on that interface with the + * same address as we're looking for. If the net is phase 2, + * generate an 802.2 and SNAP header. + */ + aa = at_ifawithnet(sat); + if (aa == NULL) { + m_freem(m); + return; + } + + eh = (struct ether_header *)sa.sa_data; + + if (aa->aa_flags & AFA_PHASE2) { + bcopy(atmulticastaddr, eh->ether_dhost, + sizeof(eh->ether_dhost)); + eh->ether_type = htons(sizeof(struct llc) + + sizeof(struct ether_aarp)); + M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); + if (m == NULL) { + ifa_free(&aa->aa_ifa); + return; + } + llc = mtod(m, struct llc *); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + bcopy(aarp_org_code, llc->llc_org_code, + sizeof(aarp_org_code)); + llc->llc_ether_type = htons(ETHERTYPE_AARP); + bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet, + sizeof(ea->aarp_spnet)); + bcopy(&sat->sat_addr.s_net, ea->aarp_tpnet, + sizeof(ea->aarp_tpnet)); + ea->aarp_spnode = AA_SAT(aa)->sat_addr.s_node; + ea->aarp_tpnode = sat->sat_addr.s_node; + } else { + bcopy(ifp->if_broadcastaddr, (caddr_t)eh->ether_dhost, + sizeof(eh->ether_dhost)); + eh->ether_type = htons(ETHERTYPE_AARP); + ea->aarp_spa = AA_SAT(aa)->sat_addr.s_node; + ea->aarp_tpa = sat->sat_addr.s_node; + } + +#ifdef NETATALKDEBUG + printf("aarp: sending request for %u.%u\n", + ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node); +#endif /* NETATALKDEBUG */ + ifa_free(&aa->aa_ifa); + + sa.sa_len = sizeof(struct sockaddr); + sa.sa_family = AF_UNSPEC; + ifp->if_output(ifp, m, &sa, NULL); +} + +int +aarpresolve(struct ifnet *ifp, struct mbuf *m, struct sockaddr_at *destsat, + u_char *desten) +{ + struct at_ifaddr *aa; + struct aarptab *aat; + + AT_IFADDR_RLOCK(); + if (at_broadcast(destsat)) { + m->m_flags |= M_BCAST; + if ((aa = at_ifawithnet_locked(destsat)) == NULL) { + AT_IFADDR_RUNLOCK(); + m_freem(m); + return (0); + } + if (aa->aa_flags & AFA_PHASE2) + bcopy(atmulticastaddr, (caddr_t)desten, + sizeof(atmulticastaddr)); + else + bcopy(ifp->if_broadcastaddr, (caddr_t)desten, + sizeof(ifp->if_addrlen)); + AT_IFADDR_RUNLOCK(); + return (1); + } + AT_IFADDR_RUNLOCK(); + + AARPTAB_LOCK(); + AARPTAB_LOOK(aat, destsat->sat_addr); + if (aat == NULL) { + /* No entry. */ + aat = aarptnew(&destsat->sat_addr); + + /* We should fail more gracefully. */ + if (aat == NULL) + panic("aarpresolve: no free entry"); + goto done; + } + + /* Found an entry. */ + aat->aat_timer = 0; + if (aat->aat_flags & ATF_COM) { + /* Entry is COMplete. */ + bcopy((caddr_t)aat->aat_enaddr, (caddr_t)desten, + sizeof(aat->aat_enaddr)); + AARPTAB_UNLOCK(); + return (1); + } + + /* Entry has not completed. */ + if (aat->aat_hold) + m_freem(aat->aat_hold); +done: + aat->aat_hold = m; + AARPTAB_UNLOCK(); + aarpwhohas(ifp, destsat); + return (0); +} + +void +aarpintr(struct mbuf *m) +{ + struct arphdr *ar; + struct ifnet *ifp; + + ifp = m->m_pkthdr.rcvif; + if (ifp->if_flags & IFF_NOARP) + goto out; + + if (m->m_len < sizeof(struct arphdr)) + goto out; + + ar = mtod(m, struct arphdr *); + if (ntohs(ar->ar_hrd) != AARPHRD_ETHER) + goto out; + + if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + + 2 * ar->ar_pln) + goto out; + + switch(ntohs(ar->ar_pro)) { + case ETHERTYPE_AT: + at_aarpinput(ifp, m); + return; + default: + break; + } + +out: + m_freem(m); +} + +static void +at_aarpinput(struct ifnet *ifp, struct mbuf *m) +{ + struct ether_aarp *ea; + struct at_ifaddr *aa; + struct aarptab *aat; + struct ether_header *eh; + struct llc *llc; + struct sockaddr_at sat; + struct sockaddr sa; + struct at_addr spa, tpa, ma; + int op; + u_short net; + + ea = mtod(m, struct ether_aarp *); + + /* Check to see if from my hardware address. */ + if (!bcmp((caddr_t)ea->aarp_sha, IF_LLADDR(ifp), ETHER_ADDR_LEN)) { + m_freem(m); + return; + } + + /* Don't accept requests from broadcast address. */ + if (!bcmp(ea->aarp_sha, ifp->if_broadcastaddr, ifp->if_addrlen)) { + log(LOG_ERR, "aarp: source link address is broadcast\n"); + m_freem(m); + return; + } + + op = ntohs(ea->aarp_op); + bcopy(ea->aarp_tpnet, &net, sizeof(net)); + + if (net != 0) { + /* Should be ATADDR_ANYNET? */ + sat.sat_len = sizeof(struct sockaddr_at); + sat.sat_family = AF_APPLETALK; + sat.sat_addr.s_net = net; + aa = at_ifawithnet(&sat); + if (aa == NULL) { + m_freem(m); + return; + } + bcopy(ea->aarp_spnet, &spa.s_net, sizeof(spa.s_net)); + bcopy(ea->aarp_tpnet, &tpa.s_net, sizeof(tpa.s_net)); + } else { + /* + * Since we don't know the net, we just look for the first + * phase 1 address on the interface. + */ + IF_ADDR_LOCK(ifp); + for (aa = (struct at_ifaddr *)TAILQ_FIRST(&ifp->if_addrhead); + aa; + aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) { + if (AA_SAT(aa)->sat_family == AF_APPLETALK && + (aa->aa_flags & AFA_PHASE2) == 0) { + break; + } + } + if (aa == NULL) { + IF_ADDR_UNLOCK(ifp); + m_freem(m); + return; + } + ifa_ref(&aa->aa_ifa); + IF_ADDR_UNLOCK(ifp); + tpa.s_net = spa.s_net = AA_SAT(aa)->sat_addr.s_net; + } + + spa.s_node = ea->aarp_spnode; + tpa.s_node = ea->aarp_tpnode; + ma.s_net = AA_SAT(aa)->sat_addr.s_net; + ma.s_node = AA_SAT(aa)->sat_addr.s_node; + + /* + * This looks like it's from us. + */ + if (spa.s_net == ma.s_net && spa.s_node == ma.s_node) { + if (aa->aa_flags & AFA_PROBING) { + /* + * We're probing, someone either responded to our + * probe, or probed for the same address we'd like to + * use. Change the address we're probing for. + */ + callout_stop(&aa->aa_callout); + wakeup(aa); + ifa_free(&aa->aa_ifa); + m_freem(m); + return; + } else if (op != AARPOP_PROBE) { + /* + * This is not a probe, and we're not probing. This + * means that someone's saying they have the same + * source address as the one we're using. Get upset. + */ + ifa_free(&aa->aa_ifa); + log(LOG_ERR, + "aarp: duplicate AT address!! %x:%x:%x:%x:%x:%x\n", + ea->aarp_sha[0], ea->aarp_sha[1], + ea->aarp_sha[2], ea->aarp_sha[3], + ea->aarp_sha[4], ea->aarp_sha[5]); + m_freem(m); + return; + } + } + + AARPTAB_LOCK(); + AARPTAB_LOOK(aat, spa); + if (aat != NULL) { + if (op == AARPOP_PROBE) { + /* + * Someone's probing for spa, dealocate the one we've + * got, so that if the prober keeps the address, + * we'll be able to arp for him. + */ + aarptfree(aat); + AARPTAB_UNLOCK(); + ifa_free(&aa->aa_ifa); + m_freem(m); + return; + } + + bcopy((caddr_t)ea->aarp_sha, (caddr_t)aat->aat_enaddr, + sizeof(ea->aarp_sha)); + aat->aat_flags |= ATF_COM; + if (aat->aat_hold) { + struct mbuf *mhold = aat->aat_hold; + aat->aat_hold = NULL; + AARPTAB_UNLOCK(); + sat.sat_len = sizeof(struct sockaddr_at); + sat.sat_family = AF_APPLETALK; + sat.sat_addr = spa; + (*ifp->if_output)(ifp, mhold, + (struct sockaddr *)&sat, NULL); /* XXX */ + } else + AARPTAB_UNLOCK(); + } else if ((tpa.s_net == ma.s_net) && (tpa.s_node == ma.s_node) + && (op != AARPOP_PROBE) && ((aat = aarptnew(&spa)) != NULL)) { + bcopy((caddr_t)ea->aarp_sha, (caddr_t)aat->aat_enaddr, + sizeof(ea->aarp_sha)); + aat->aat_flags |= ATF_COM; + AARPTAB_UNLOCK(); + } else + AARPTAB_UNLOCK(); + + /* + * Don't respond to responses, and never respond if we're still + * probing. + */ + if (tpa.s_net != ma.s_net || tpa.s_node != ma.s_node || + op == AARPOP_RESPONSE || (aa->aa_flags & AFA_PROBING)) { + ifa_free(&aa->aa_ifa); + m_freem(m); + return; + } + + bcopy((caddr_t)ea->aarp_sha, (caddr_t)ea->aarp_tha, + sizeof(ea->aarp_sha)); + bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha, sizeof(ea->aarp_sha)); + + /* XXX */ + eh = (struct ether_header *)sa.sa_data; + bcopy((caddr_t)ea->aarp_tha, (caddr_t)eh->ether_dhost, + sizeof(eh->ether_dhost)); + + if (aa->aa_flags & AFA_PHASE2) { + eh->ether_type = htons(sizeof(struct llc) + + sizeof(struct ether_aarp)); + M_PREPEND(m, sizeof(struct llc), M_DONTWAIT); + if (m == NULL) { + ifa_free(&aa->aa_ifa); + return; + } + llc = mtod(m, struct llc *); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + bcopy(aarp_org_code, llc->llc_org_code, + sizeof(aarp_org_code)); + llc->llc_ether_type = htons(ETHERTYPE_AARP); + + bcopy(ea->aarp_spnet, ea->aarp_tpnet, + sizeof(ea->aarp_tpnet)); + bcopy(&ma.s_net, ea->aarp_spnet, sizeof(ea->aarp_spnet)); + } else + eh->ether_type = htons(ETHERTYPE_AARP); + ifa_free(&aa->aa_ifa); + + ea->aarp_tpnode = ea->aarp_spnode; + ea->aarp_spnode = ma.s_node; + ea->aarp_op = htons(AARPOP_RESPONSE); + + sa.sa_len = sizeof(struct sockaddr); + sa.sa_family = AF_UNSPEC; + (*ifp->if_output)(ifp, m, &sa, NULL); /* XXX */ + return; +} + +static void +aarptfree(struct aarptab *aat) +{ + + AARPTAB_LOCK_ASSERT(); + if (aat->aat_hold) + m_freem(aat->aat_hold); + aat->aat_hold = NULL; + aat->aat_timer = aat->aat_flags = 0; + aat->aat_ataddr.s_net = 0; + aat->aat_ataddr.s_node = 0; +} + +struct aarptab * +aarptnew(struct at_addr *addr) +{ + int n; + int oldest = -1; + struct aarptab *aat, *aato = NULL; + static int first = 1; + + AARPTAB_LOCK_ASSERT(); + if (first) { + first = 0; + aarptimer_ch = timeout(aarptimer, (caddr_t)0, hz); + } + aat = &aarptab[AARPTAB_HASH(*addr) * AARPTAB_BSIZ]; + for (n = 0; n < AARPTAB_BSIZ; n++, aat++) { + if (aat->aat_flags == 0) + goto out; + if (aat->aat_flags & ATF_PERM) + continue; + if ((int) aat->aat_timer > oldest) { + oldest = aat->aat_timer; + aato = aat; + } + } + if (aato == NULL) + return (NULL); + aat = aato; + aarptfree(aat); +out: + aat->aat_ataddr = *addr; + aat->aat_flags = ATF_INUSE; + return (aat); +} + + +void +aarpprobe(void *arg) +{ + struct ifnet *ifp = arg; + struct mbuf *m; + struct ether_header *eh; + struct ether_aarp *ea; + struct at_ifaddr *aa; + struct llc *llc; + struct sockaddr sa; + + /* + * We need to check whether the output ethernet type should be phase + * 1 or 2. We have the interface that we'll be sending the aarp out. + * We need to find an AppleTalk network on that interface with the + * same address as we're looking for. If the net is phase 2, + * generate an 802.2 and SNAP header. + */ + AARPTAB_LOCK(); + for (aa = (struct at_ifaddr *)TAILQ_FIRST(&ifp->if_addrhead); aa; + aa = (struct at_ifaddr *)aa->aa_ifa.ifa_link.tqe_next) { + if (AA_SAT(aa)->sat_family == AF_APPLETALK && + (aa->aa_flags & AFA_PROBING)) + break; + } + if (aa == NULL) { + /* Serious error XXX. */ + AARPTAB_UNLOCK(); + printf("aarpprobe why did this happen?!\n"); + return; + } + + if (aa->aa_probcnt <= 0) { + aa->aa_flags &= ~AFA_PROBING; + wakeup(aa); + AARPTAB_UNLOCK(); + return; + } else + callout_reset(&aa->aa_callout, hz / 5, aarpprobe, ifp); + ifa_ref(&aa->aa_ifa); + AARPTAB_UNLOCK(); + + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m == NULL) { + ifa_free(&aa->aa_ifa); + return; + } +#ifdef MAC + mac_netatalk_aarp_send(ifp, m); +#endif + m->m_len = sizeof(*ea); + m->m_pkthdr.len = sizeof(*ea); + MH_ALIGN(m, sizeof(*ea)); + + ea = mtod(m, struct ether_aarp *); + bzero((caddr_t)ea, sizeof(*ea)); + + ea->aarp_hrd = htons(AARPHRD_ETHER); + ea->aarp_pro = htons(ETHERTYPE_AT); + ea->aarp_hln = sizeof(ea->aarp_sha); + ea->aarp_pln = sizeof(ea->aarp_spu); + ea->aarp_op = htons(AARPOP_PROBE); + bcopy(IF_LLADDR(ifp), (caddr_t)ea->aarp_sha, + sizeof(ea->aarp_sha)); + + eh = (struct ether_header *)sa.sa_data; + + if (aa->aa_flags & AFA_PHASE2) { + bcopy(atmulticastaddr, eh->ether_dhost, + sizeof(eh->ether_dhost)); + eh->ether_type = htons(sizeof(struct llc) + + sizeof(struct ether_aarp)); + M_PREPEND(m, sizeof(struct llc), M_WAIT); + llc = mtod(m, struct llc *); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + bcopy(aarp_org_code, llc->llc_org_code, + sizeof(aarp_org_code)); + llc->llc_ether_type = htons(ETHERTYPE_AARP); + + bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_spnet, + sizeof(ea->aarp_spnet)); + bcopy(&AA_SAT(aa)->sat_addr.s_net, ea->aarp_tpnet, + sizeof(ea->aarp_tpnet)); + ea->aarp_spnode = ea->aarp_tpnode = + AA_SAT(aa)->sat_addr.s_node; + } else { + bcopy(ifp->if_broadcastaddr, (caddr_t)eh->ether_dhost, + sizeof(eh->ether_dhost)); + eh->ether_type = htons(ETHERTYPE_AARP); + ea->aarp_spa = ea->aarp_tpa = AA_SAT(aa)->sat_addr.s_node; + } + +#ifdef NETATALKDEBUG + printf("aarp: sending probe for %u.%u\n", + ntohs(AA_SAT(aa)->sat_addr.s_net), AA_SAT(aa)->sat_addr.s_node); +#endif /* NETATALKDEBUG */ + ifa_free(&aa->aa_ifa); + + sa.sa_len = sizeof(struct sockaddr); + sa.sa_family = AF_UNSPEC; + (*ifp->if_output)(ifp, m, &sa, NULL); /* XXX */ + aa->aa_probcnt--; +} + +void +aarp_clean(void) +{ + struct aarptab *aat; + int i; + + untimeout(aarptimer, 0, aarptimer_ch); + AARPTAB_LOCK(); + for (i = 0, aat = aarptab; i < AARPTAB_SIZE; i++, aat++) { + if (aat->aat_hold) { + m_freem(aat->aat_hold); + aat->aat_hold = NULL; + } + } + AARPTAB_UNLOCK(); +} diff --git a/freebsd/netatalk/aarp.h b/freebsd/netatalk/aarp.h new file mode 100644 index 00000000..4d7e06ac --- /dev/null +++ b/freebsd/netatalk/aarp.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ + */ + +#ifndef _NETATALK_AARP_HH_ +#define _NETATALK_AARP_HH_ + +/* + * This structure is used for both phase 1 and 2. Under phase 1 + * the net is not filled in. It is in phase 2. In both cases, the + * hardware address length is (for some unknown reason) 4. If + * anyone at Apple could program their way out of paper bag, it + * would be 1 and 3 respectively for phase 1 and 2. + */ +union aapa { + u_char ap_pa[4]; + struct ap_node { + u_char an_zero; + u_char an_net[2]; + u_char an_node; + } __packed ap_node; +}; + +struct ether_aarp { + struct arphdr eaa_hdr; + u_char aarp_sha[6]; + union aapa aarp_spu; + u_char aarp_tha[6]; + union aapa aarp_tpu; +} __packed; + +#define aarp_hrd eaa_hdr.ar_hrd +#define aarp_pro eaa_hdr.ar_pro +#define aarp_hln eaa_hdr.ar_hln +#define aarp_pln eaa_hdr.ar_pln +#define aarp_op eaa_hdr.ar_op +#define aarp_spa aarp_spu.ap_node.an_node +#define aarp_tpa aarp_tpu.ap_node.an_node +#define aarp_spnet aarp_spu.ap_node.an_net +#define aarp_tpnet aarp_tpu.ap_node.an_net +#define aarp_spnode aarp_spu.ap_node.an_node +#define aarp_tpnode aarp_tpu.ap_node.an_node + +struct aarptab { + struct at_addr aat_ataddr; + u_char aat_enaddr[6]; + u_char aat_timer; + u_char aat_flags; + struct mbuf *aat_hold; +}; + +#define AARPHRD_ETHER 0x0001 + +#define AARPOP_REQUEST 0x01 +#define AARPOP_RESPONSE 0x02 +#define AARPOP_PROBE 0x03 + +#ifdef _KERNEL +struct aarptab *aarptnew(struct at_addr *); +#endif + +#endif /* _NETATALK_AARP_HH_ */ diff --git a/freebsd/netatalk/at.h b/freebsd/netatalk/at.h new file mode 100644 index 00000000..5b4597a0 --- /dev/null +++ b/freebsd/netatalk/at.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + * + * $FreeBSD$ + */ + +#ifndef _NETATALK_AT_HH_ +#define _NETATALK_AT_HH_ + +/* + * Supported protocols + */ +#define ATPROTO_DDP 0 +#define ATPROTO_AARP 254 + +#define DDP_MAXSZ 587 + +/* + * If ATPORT_FIRST <= Port < ATPORT_RESERVED, the port was created by a + * privileged process. + * + * If ATPORT_RESERVED <= Port < ATPORT_LAST, the port was not necessarily + * created by a privileged process. + */ +#define ATPORT_FIRST 1 +#define ATPORT_RESERVED 128 +#define ATPORT_LAST 255 + +/* + * AppleTalk address. + */ +struct at_addr { + u_short s_net; + u_char s_node; +}; + +#define ATADDR_ANYNET (u_short)0x0000 +#define ATADDR_ANYNODE (u_char)0x00 +#define ATADDR_ANYPORT (u_char)0x00 +#define ATADDR_BCAST (u_char)0xff /* There is no BCAST for NET. */ + +struct netrange { + u_char nr_phase; + u_short nr_firstnet; + u_short nr_lastnet; +}; + +/* + * Socket address, AppleTalk style. We keep magic information in the zero + * bytes. There are three types, NONE, CONFIG which has the phase and a net + * range, and IFACE which has the network address of an interface. IFACE may + * be filled in by the client, and is filled in by the kernel. + */ +struct sockaddr_at { + u_char sat_len; + u_char sat_family; + u_char sat_port; + struct at_addr sat_addr; + union { + struct netrange r_netrange; + char r_zero[8]; /* Hide struct netrange here. */ + } sat_range; +}; + +#define sat_zero sat_range.r_zero + +#endif /* !_NETATALK_AT_HH_ */ diff --git a/freebsd/netatalk/at_control.c b/freebsd/netatalk/at_control.c new file mode 100644 index 00000000..c03d2ad8 --- /dev/null +++ b/freebsd/netatalk/at_control.c @@ -0,0 +1,888 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * Copyright (c) 2009 Robert N. M. Watson + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + */ + +#include <freebsd/sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <freebsd/sys/param.h> +#include <freebsd/sys/systm.h> +#include <freebsd/sys/sockio.h> +#include <freebsd/sys/lock.h> +#include <freebsd/sys/malloc.h> +#include <freebsd/sys/kernel.h> +#include <freebsd/sys/priv.h> +#include <freebsd/sys/rwlock.h> +#include <freebsd/sys/socket.h> +#include <freebsd/net/if.h> +#include <freebsd/net/route.h> +#include <freebsd/netinet/in.h> +#undef s_net +#include <freebsd/netinet/if_ether.h> + +#include <freebsd/netatalk/at.h> +#include <freebsd/netatalk/at_var.h> +#include <freebsd/netatalk/at_extern.h> + +struct rwlock at_ifaddr_rw; +struct at_ifaddrhead at_ifaddrhead; + +RW_SYSINIT(at_ifaddr_rw, &at_ifaddr_rw, "at_ifaddr_rw"); + +static int aa_dorangeroute(struct ifaddr *ifa, u_int first, u_int last, + int cmd); +static int aa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, + struct at_addr *mask); +static int aa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, + struct at_addr *mask); +static int aa_dosingleroute(struct ifaddr *ifa, struct at_addr *addr, + struct at_addr *mask, int cmd, int flags); +static int at_scrub(struct ifnet *ifp, struct at_ifaddr *aa); +static int at_ifinit(struct ifnet *ifp, struct at_ifaddr *aa, + struct sockaddr_at *sat); +static int aa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw); + +#define sateqaddr(a,b) \ + ((a)->sat_len == (b)->sat_len && \ + (a)->sat_family == (b)->sat_family && \ + (a)->sat_addr.s_net == (b)->sat_addr.s_net && \ + (a)->sat_addr.s_node == (b)->sat_addr.s_node) + +int +at_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, + struct thread *td) +{ + struct ifreq *ifr = (struct ifreq *)data; + struct sockaddr_at *sat; + struct netrange *nr; + struct at_aliasreq *ifra = (struct at_aliasreq *)data; + struct at_ifaddr *aa; + struct ifaddr *ifa; + int error; + + /* + * If we have an ifp, then find the matching at_ifaddr if it exists + */ + aa = NULL; + AT_IFADDR_RLOCK(); + if (ifp != NULL) { + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if (aa->aa_ifp == ifp) + break; + } + } + if (aa != NULL) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + + /* + * In this first switch table we are basically getting ready for + * the second one, by getting the atalk-specific things set up + * so that they start to look more similar to other protocols etc. + */ + error = 0; + switch (cmd) { + case SIOCAIFADDR: + case SIOCDIFADDR: + /* + * If we have an appletalk sockaddr, scan forward of where we + * are now on the at_ifaddr list to find one with a matching + * address on this interface. This may leave aa pointing to + * the first address on the NEXT interface! + */ + if (ifra->ifra_addr.sat_family == AF_APPLETALK) { + struct at_ifaddr *oaa; + + AT_IFADDR_RLOCK(); + for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { + if (aa->aa_ifp == ifp && + sateqaddr(&aa->aa_addr, &ifra->ifra_addr)) + break; + } + if (oaa != NULL && oaa != aa) + ifa_free(&oaa->aa_ifa); + if (aa != NULL && oaa != aa) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + } + /* + * If we a retrying to delete an addres but didn't find such, + * then rewurn with an error + */ + if (cmd == SIOCDIFADDR && aa == NULL) { + error = EADDRNOTAVAIL; + goto out; + } + /*FALLTHROUGH*/ + + case SIOCSIFADDR: + /* + * If we are not superuser, then we don't get to do these ops. + * + * XXXRW: Layering? + */ + if (priv_check(td, PRIV_NET_ADDIFADDR)) { + error = EPERM; + goto out; + } + + sat = satosat(&ifr->ifr_addr); + nr = (struct netrange *)sat->sat_zero; + if (nr->nr_phase == 1) { + struct at_ifaddr *oaa; + + /* + * Look for a phase 1 address on this interface. + * This may leave aa pointing to the first address on + * the NEXT interface! + */ + AT_IFADDR_RLOCK(); + for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { + if (aa->aa_ifp == ifp && + (aa->aa_flags & AFA_PHASE2) == 0) + break; + } + if (oaa != NULL && oaa != aa) + ifa_free(&oaa->aa_ifa); + if (aa != NULL && oaa != aa) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + } else { /* default to phase 2 */ + struct at_ifaddr *oaa; + + /* + * Look for a phase 2 address on this interface. + * This may leave aa pointing to the first address on + * the NEXT interface! + */ + AT_IFADDR_RLOCK(); + for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { + if (aa->aa_ifp == ifp && (aa->aa_flags & + AFA_PHASE2)) + break; + } + if (oaa != NULL && oaa != aa) + ifa_free(&oaa->aa_ifa); + if (aa != NULL && oaa != aa) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + } + + if (ifp == NULL) + panic("at_control"); + + /* + * If we failed to find an existing at_ifaddr entry, then we + * allocate a fresh one. + */ + if (aa == NULL) { + aa = malloc(sizeof(struct at_ifaddr), M_IFADDR, + M_NOWAIT | M_ZERO); + if (aa == NULL) { + error = ENOBUFS; + goto out; + } + callout_init(&aa->aa_callout, CALLOUT_MPSAFE); + + ifa = (struct ifaddr *)aa; + ifa_init(ifa); + + /* + * As the at_ifaddr contains the actual sockaddrs, + * and the ifaddr itself, link them all together + * correctly. + */ + ifa->ifa_addr = (struct sockaddr *)&aa->aa_addr; + ifa->ifa_dstaddr = (struct sockaddr *)&aa->aa_addr; + ifa->ifa_netmask = (struct sockaddr *)&aa->aa_netmask; + + /* + * Set/clear the phase 2 bit. + */ + if (nr->nr_phase == 1) + aa->aa_flags &= ~AFA_PHASE2; + else + aa->aa_flags |= AFA_PHASE2; + + ifa_ref(&aa->aa_ifa); /* at_ifaddrhead */ + AT_IFADDR_WLOCK(); + if (!TAILQ_EMPTY(&at_ifaddrhead)) { + /* + * Don't let the loopback be first, since the + * first address is the machine's default + * address for binding. If it is, stick + * ourself in front, otherwise go to the back + * of the list. + */ + if (TAILQ_FIRST(&at_ifaddrhead)->aa_ifp-> + if_flags & IFF_LOOPBACK) + TAILQ_INSERT_HEAD(&at_ifaddrhead, aa, + aa_link); + else + TAILQ_INSERT_TAIL(&at_ifaddrhead, aa, + aa_link); + } else + TAILQ_INSERT_HEAD(&at_ifaddrhead, aa, + aa_link); + AT_IFADDR_WUNLOCK(); + + /* + * and link it all together + */ + aa->aa_ifp = ifp; + ifa_ref(&aa->aa_ifa); /* if_addrhead */ + IF_ADDR_LOCK(ifp); + TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); + IF_ADDR_UNLOCK(ifp); + } else { + /* + * If we DID find one then we clobber any routes + * dependent on it.. + */ + at_scrub(ifp, aa); + } + break; + + case SIOCGIFADDR : + sat = satosat(&ifr->ifr_addr); + nr = (struct netrange *)sat->sat_zero; + if (nr->nr_phase == 1) { + struct at_ifaddr *oaa; + + /* + * If the request is specifying phase 1, then + * only look at a phase one address + */ + AT_IFADDR_RLOCK(); + for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { + if (aa->aa_ifp == ifp && + (aa->aa_flags & AFA_PHASE2) == 0) + break; + } + if (oaa != NULL && oaa != aa) + ifa_free(&oaa->aa_ifa); + if (aa != NULL && oaa != aa) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + } else { + struct at_ifaddr *oaa; + + /* + * default to phase 2 + */ + AT_IFADDR_RLOCK(); + for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { + if (aa->aa_ifp == ifp && (aa->aa_flags & + AFA_PHASE2)) + break; + } + if (oaa != NULL && oaa != aa) + ifa_free(&oaa->aa_ifa); + if (aa != NULL && oaa != aa) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + } + + if (aa == NULL) { + error = EADDRNOTAVAIL; + goto out; + } + break; + } + + /* + * By the time this switch is run we should be able to assume that + * the "aa" pointer is valid when needed. + */ + switch (cmd) { + case SIOCGIFADDR: + + /* + * copy the contents of the sockaddr blindly. + */ + sat = (struct sockaddr_at *)&ifr->ifr_addr; + *sat = aa->aa_addr; + + /* + * and do some cleanups + */ + ((struct netrange *)&sat->sat_zero)->nr_phase + = (aa->aa_flags & AFA_PHASE2) ? 2 : 1; + ((struct netrange *)&sat->sat_zero)->nr_firstnet = + aa->aa_firstnet; + ((struct netrange *)&sat->sat_zero)->nr_lastnet = + aa->aa_lastnet; + break; + + case SIOCSIFADDR: + error = at_ifinit(ifp, aa, + (struct sockaddr_at *)&ifr->ifr_addr); + goto out; + + case SIOCAIFADDR: + if (sateqaddr(&ifra->ifra_addr, &aa->aa_addr)) { + error = 0; + goto out; + } + error = at_ifinit(ifp, aa, + (struct sockaddr_at *)&ifr->ifr_addr); + goto out; + + case SIOCDIFADDR: + + /* + * remove the ifaddr from the interface + */ + ifa = (struct ifaddr *)aa; + IF_ADDR_LOCK(ifp); + TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); + IF_ADDR_UNLOCK(ifp); + ifa_free(ifa); /* if_addrhead */ + + /* + * Now remove the at_ifaddr from the parallel structure + * as well, or we'd be in deep trouble + */ + + AT_IFADDR_WLOCK(); + TAILQ_REMOVE(&at_ifaddrhead, aa, aa_link); + AT_IFADDR_WUNLOCK(); + ifa_free(ifa); /* at_ifaddrhead */ + break; + + default: + if (ifp == NULL || ifp->if_ioctl == NULL) { + error = EOPNOTSUPP; + goto out; + } + error = ((*ifp->if_ioctl)(ifp, cmd, data)); + } + +out: + if (aa != NULL) + ifa_free(&aa->aa_ifa); + return (error); +} + +/* + * Given an interface and an at_ifaddr (supposedly on that interface) + * remove any routes that depend on this. + * Why ifp is needed I'm not sure, + * as aa->at_ifaddr.ifa_ifp should be the same. + */ +static int +at_scrub(struct ifnet *ifp, struct at_ifaddr *aa) +{ + int error; + + if (aa->aa_flags & AFA_ROUTE) { + if (ifp->if_flags & IFF_LOOPBACK) { + if ((error = aa_delsingleroute(&aa->aa_ifa, + &aa->aa_addr.sat_addr, &aa->aa_netmask.sat_addr)) + != 0) + return (error); + } else if (ifp->if_flags & IFF_POINTOPOINT) { + if ((error = rtinit(&aa->aa_ifa, RTM_DELETE, + RTF_HOST)) != 0) + return (error); + } else if (ifp->if_flags & IFF_BROADCAST) { + error = aa_dorangeroute(&aa->aa_ifa, + ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), + RTM_DELETE); + } + aa->aa_ifa.ifa_flags &= ~IFA_ROUTE; + aa->aa_flags &= ~AFA_ROUTE; + } + return (0); +} + +/* + * given an at_ifaddr,a sockaddr_at and an ifp, + * bang them all together at high speed and see what happens + */ +static int +at_ifinit(struct ifnet *ifp, struct at_ifaddr *aa, struct sockaddr_at *sat) +{ + struct netrange nr, onr; + struct sockaddr_at oldaddr; + int error = 0, i, j; + int netinc, nodeinc, nnets; + u_short net; + + /* + * save the old addresses in the at_ifaddr just in case we need them. + */ + oldaddr = aa->aa_addr; + onr.nr_firstnet = aa->aa_firstnet; + onr.nr_lastnet = aa->aa_lastnet; + + /* + * take the address supplied as an argument, and add it to the + * at_ifnet (also given). Remember ing to update + * those parts of the at_ifaddr that need special processing + */ + bzero(AA_SAT(aa), sizeof(struct sockaddr_at)); + bcopy(sat->sat_zero, &nr, sizeof(struct netrange)); + bcopy(sat->sat_zero, AA_SAT(aa)->sat_zero, sizeof(struct netrange)); + nnets = ntohs(nr.nr_lastnet) - ntohs(nr.nr_firstnet) + 1; + aa->aa_firstnet = nr.nr_firstnet; + aa->aa_lastnet = nr.nr_lastnet; + +/* XXX ALC */ +#if 0 + printf("at_ifinit: %s: %u.%u range %u-%u phase %d\n", + ifp->if_name, + ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, + ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), + (aa->aa_flags & AFA_PHASE2) ? 2 : 1); +#endif + + /* + * We could eliminate the need for a second phase 1 probe (post + * autoconf) if we check whether we're resetting the node. Note + * that phase 1 probes use only nodes, not net.node pairs. Under + * phase 2, both the net and node must be the same. + */ + if (ifp->if_flags & IFF_LOOPBACK) { + AA_SAT(aa)->sat_len = sat->sat_len; + AA_SAT(aa)->sat_family = AF_APPLETALK; + AA_SAT(aa)->sat_addr.s_net = sat->sat_addr.s_net; + AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node; +#if 0 + } else if (fp->if_flags & IFF_POINTOPOINT) { + /* unimplemented */ + /* + * we'd have to copy the dstaddr field over from the sat + * but it's not clear that it would contain the right info.. + */ +#endif + } else { + /* + * We are a normal (probably ethernet) interface. + * apply the new address to the interface structures etc. + * We will probe this address on the net first, before + * applying it to ensure that it is free.. If it is not, then + * we will try a number of other randomly generated addresses + * in this net and then increment the net. etc.etc. until + * we find an unused address. + */ + aa->aa_flags |= AFA_PROBING; /* not loopback we Must probe? */ + AA_SAT(aa)->sat_len = sizeof(struct sockaddr_at); + AA_SAT(aa)->sat_family = AF_APPLETALK; + if (aa->aa_flags & AFA_PHASE2) { + if (sat->sat_addr.s_net == ATADDR_ANYNET) { + /* + * If we are phase 2, and the net was not + * specified then we select a random net + * within the supplied netrange. + * XXX use /dev/random? + */ + if (nnets != 1) + net = ntohs(nr.nr_firstnet) + + time_second % (nnets - 1); + else + net = ntohs(nr.nr_firstnet); + } else { + /* + * if a net was supplied, then check that it + * is within the netrange. If it is not then + * replace the old values and return an error + */ + if (ntohs(sat->sat_addr.s_net) < + ntohs(nr.nr_firstnet) || + ntohs(sat->sat_addr.s_net) > + ntohs(nr.nr_lastnet)) { + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return (EINVAL); + } + /* + * otherwise just use the new net number.. + */ + net = ntohs(sat->sat_addr.s_net); + } + } else { + /* + * we must be phase one, so just use whatever we were + * given. I guess it really isn't going to be + * used... RIGHT? + */ + net = ntohs(sat->sat_addr.s_net); + } + + /* + * set the node part of the address into the ifaddr. + * If it's not specified, be random about it... + * XXX use /dev/random? + */ + if (sat->sat_addr.s_node == ATADDR_ANYNODE) + AA_SAT(aa)->sat_addr.s_node = time_second; + else + AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node; + + /* + * Copy the phase. + */ + AA_SAT(aa)->sat_range.r_netrange.nr_phase = + ((aa->aa_flags & AFA_PHASE2) ? 2:1); + + /* + * step through the nets in the range + * starting at the (possibly random) start point. + */ + for (i = nnets, netinc = 1; i > 0; net = + ntohs(nr.nr_firstnet) + ((net - ntohs(nr.nr_firstnet) + + netinc) % nnets), i--) { + AA_SAT(aa)->sat_addr.s_net = htons(net); + + /* + * using a rather strange stepping method, + * stagger through the possible node addresses + * Once again, starting at the (possibly random) + * initial node address. + */ + for (j = 0, nodeinc = time_second | 1; j < 256; + j++, AA_SAT(aa)->sat_addr.s_node += nodeinc) { + if (AA_SAT(aa)->sat_addr.s_node > 253 || + AA_SAT(aa)->sat_addr.s_node < 1) + continue; + aa->aa_probcnt = 10; + + /* + * start off the probes as an asynchronous + * activity. though why wait 200mSec? + */ + AARPTAB_LOCK(); + callout_reset(&aa->aa_callout, hz / 5, + aarpprobe, ifp); + if (msleep(aa, &aarptab_mtx, PPAUSE|PCATCH, + "at_ifinit", 0)) { + AARPTAB_UNLOCK(); + /* + * theoretically we shouldn't time + * out here so if we returned with an + * error.. + */ + printf("at_ifinit: why did this " + "happen?!\n"); + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return (EINTR); + } + AARPTAB_UNLOCK(); + + /* + * The async activity should have woken us + * up. We need to see if it was successful + * in finding a free spot, or if we need to + * iterate to the next address to try. + */ + if ((aa->aa_flags & AFA_PROBING) == 0) + break; + } + + /* + * of course we need to break out through two loops... + */ + if ((aa->aa_flags & AFA_PROBING) == 0) + break; + /* reset node for next network */ + AA_SAT(aa)->sat_addr.s_node = time_second; + } + + /* + * if we are still trying to probe, then we have finished all + * the possible addresses, so we need to give up + */ + if (aa->aa_flags & AFA_PROBING) { + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return (EADDRINUSE); + } + } + + /* + * Now that we have selected an address, we need to tell the interface + * about it, just in case it needs to adjust something. + */ + if (ifp->if_ioctl != NULL && + (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)aa))) { + /* + * of course this could mean that it objects violently + * so if it does, we back out again.. + */ + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return (error); + } + + /* + * set up the netmask part of the at_ifaddr + * and point the appropriate pointer in the ifaddr to it. + * probably pointless, but what the heck.. XXX + */ + bzero(&aa->aa_netmask, sizeof(aa->aa_netmask)); + aa->aa_netmask.sat_len = sizeof(struct sockaddr_at); + aa->aa_netmask.sat_family = AF_APPLETALK; + aa->aa_netmask.sat_addr.s_net = 0xffff; + aa->aa_netmask.sat_addr.s_node = 0; + aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); /* XXX */ + + /* + * Initialize broadcast (or remote p2p) address + */ + bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr)); + aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at); + aa->aa_broadaddr.sat_family = AF_APPLETALK; + + aa->aa_ifa.ifa_metric = ifp->if_metric; + if (ifp->if_flags & IFF_BROADCAST) { + aa->aa_broadaddr.sat_addr.s_net = htons(0); + aa->aa_broadaddr.sat_addr.s_node = 0xff; + aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) + &aa->aa_broadaddr; + /* add the range of routes needed */ + error = aa_dorangeroute(&aa->aa_ifa, ntohs(aa->aa_firstnet), + ntohs(aa->aa_lastnet), RTM_ADD); + } else if (ifp->if_flags & IFF_POINTOPOINT) { + struct at_addr rtaddr, rtmask; + + bzero(&rtaddr, sizeof(rtaddr)); + bzero(&rtmask, sizeof(rtmask)); + /* fill in the far end if we know it here XXX */ + aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_dstaddr; + error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); + } else if (ifp->if_flags & IFF_LOOPBACK) { + struct at_addr rtaddr, rtmask; + + bzero(&rtaddr, sizeof(rtaddr)); + bzero(&rtmask, sizeof(rtmask)); + rtaddr.s_net = AA_SAT(aa)->sat_addr.s_net; + rtaddr.s_node = AA_SAT(aa)->sat_addr.s_node; + rtmask.s_net = 0xffff; + /* XXX should not be so.. should be HOST route */ + rtmask.s_node = 0x0; + error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); + } + + /* + * set the address of our "check if this addr is ours" routine. + */ + aa->aa_ifa.ifa_claim_addr = aa_claim_addr; + + /* + * of course if we can't add these routes we back out, but it's + * getting risky by now XXX + */ + if (error) { + at_scrub(ifp, aa); + aa->aa_addr = oldaddr; + aa->aa_firstnet = onr.nr_firstnet; + aa->aa_lastnet = onr.nr_lastnet; + return (error); + } + + /* + * note that the address has a route associated with it.... + */ + aa->aa_ifa.ifa_flags |= IFA_ROUTE; + aa->aa_flags |= AFA_ROUTE; + return (0); +} + +/* + * check whether a given address is a broadcast address for us.. + */ +int +at_broadcast(struct sockaddr_at *sat) +{ + struct at_ifaddr *aa; + + AT_IFADDR_LOCK_ASSERT(); + + /* + * If the node is not right, it can't be a broadcast + */ + if (sat->sat_addr.s_node != ATADDR_BCAST) + return (0); + + /* + * If the node was right then if the net is right, it's a broadcast + */ + if (sat->sat_addr.s_net == ATADDR_ANYNET) + return (1); + + /* + * failing that, if the net is one we have, it's a broadcast as well. + */ + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if ((aa->aa_ifp->if_flags & IFF_BROADCAST) + && (ntohs(sat->sat_addr.s_net) >= ntohs(aa->aa_firstnet) + && ntohs(sat->sat_addr.s_net) <= ntohs(aa->aa_lastnet))) + return (1); + } + return (0); +} + +/* + * aa_dorangeroute() + * + * Add a route for a range of networks from bot to top - 1. + * Algorithm: + * + * Split the range into two subranges such that the middle + * of the two ranges is the point where the highest bit of difference + * between the two addresses makes its transition. + * Each of the upper and lower ranges might not exist, or might be + * representable by 1 or more netmasks. In addition, if both + * ranges can be represented by the same netmask, then they can be merged + * by using the next higher netmask.. + */ + +static int +aa_dorangeroute(struct ifaddr *ifa, u_int bot, u_int top, int cmd) +{ + u_int mask1; + struct at_addr addr; + struct at_addr mask; + int error; + + /* + * slight sanity check + */ + if (bot > top) return (EINVAL); + + addr.s_node = 0; + mask.s_node = 0; + /* + * just start out with the lowest boundary + * and keep extending the mask till it's too big. + */ + + while (bot <= top) { + mask1 = 1; + while (((bot & ~mask1) >= bot) && ((bot | mask1) <= top)) { + mask1 <<= 1; + mask1 |= 1; + } + mask1 >>= 1; + mask.s_net = htons(~mask1); + addr.s_net = htons(bot); + if (cmd == RTM_ADD) { + error = aa_addsingleroute(ifa,&addr,&mask); + if (error) { + /* XXX clean up? */ + return (error); + } + } else + error = aa_delsingleroute(ifa,&addr,&mask); + bot = (bot | mask1) + 1; + } + return (0); +} + +static int +aa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, + struct at_addr *mask) +{ + +#if 0 + printf("aa_addsingleroute: %x.%x mask %x.%x ...\n", + ntohs(addr->s_net), addr->s_node, ntohs(mask->s_net), + mask->s_node); +#endif + + return (aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP)); +} + +static int +aa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, + struct at_addr *mask) +{ + + return (aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0)); +} + +static int +aa_dosingleroute(struct ifaddr *ifa, struct at_addr *at_addr, + struct at_addr *at_mask, int cmd, int flags) +{ + struct sockaddr_at addr, mask; + + bzero(&addr, sizeof(addr)); + bzero(&mask, sizeof(mask)); + addr.sat_family = AF_APPLETALK; + addr.sat_len = sizeof(struct sockaddr_at); + addr.sat_addr.s_net = at_addr->s_net; + addr.sat_addr.s_node = at_addr->s_node; + mask.sat_family = AF_APPLETALK; + mask.sat_len = sizeof(struct sockaddr_at); + mask.sat_addr.s_net = at_mask->s_net; + mask.sat_addr.s_node = at_mask->s_node; + if (at_mask->s_node) + flags |= RTF_HOST; + return (rtrequest(cmd, (struct sockaddr *) &addr, + (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr), + (struct sockaddr *) &mask, flags, NULL)); +} + +static int +aa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw0) +{ + struct sockaddr_at *addr = (struct sockaddr_at *)ifa->ifa_addr; + struct sockaddr_at *gw = (struct sockaddr_at *)gw0; + + switch (gw->sat_range.r_netrange.nr_phase) { + case 1: + if(addr->sat_range.r_netrange.nr_phase == 1) + return (1); + + case 0: + case 2: + /* + * if it's our net (including 0), + * or netranges are valid, and we are in the range, + * then it's ours. + */ + if ((addr->sat_addr.s_net == gw->sat_addr.s_net) + || ((addr->sat_range.r_netrange.nr_lastnet) + && (ntohs(gw->sat_addr.s_net) >= + ntohs(addr->sat_range.r_netrange.nr_firstnet)) + && (ntohs(gw->sat_addr.s_net) <= + ntohs(addr->sat_range.r_netrange.nr_lastnet)))) + return (1); + break; + default: + printf("atalk: bad phase\n"); + } + return (0); +} diff --git a/freebsd/netatalk/at_extern.h b/freebsd/netatalk/at_extern.h new file mode 100644 index 00000000..aebae73c --- /dev/null +++ b/freebsd/netatalk/at_extern.h @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 1990,1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ + */ + +#ifndef _NETATALK_AT_EXTERN_HH_ +#define _NETATALK_AT_EXTERN_HH_ + +extern struct mtx aarptab_mtx; + +#define AARPTAB_LOCK() mtx_lock(&aarptab_mtx) +#define AARPTAB_UNLOCK() mtx_unlock(&aarptab_mtx) +#define AARPTAB_LOCK_ASSERT() mtx_assert(&aarptab_mtx, MA_OWNED) +#define AARPTAB_UNLOCK_ASSERT() mtx_assert(&aarptab_mtx, MA_NOTOWNED) + +struct at_ifaddr; +struct ifnet; +struct mbuf; +struct route; +struct thread; +struct sockaddr_at; +struct socket; +void aarpintr(struct mbuf *); +void aarpprobe(void *arg); +int aarpresolve(struct ifnet *, struct mbuf *, + struct sockaddr_at *, u_char *); +void aarp_clean(void); +void at1intr(struct mbuf *); +void at2intr(struct mbuf *); +int at_broadcast(struct sockaddr_at *); +u_short at_cksum(struct mbuf *m, int skip); +int at_control(struct socket *so, u_long cmd, caddr_t data, + struct ifnet *ifp, struct thread *td); +struct at_ifaddr *at_ifawithnet(struct sockaddr_at *); +struct at_ifaddr *at_ifawithnet_locked(struct sockaddr_at *sat); + +int at_inithead(void**, int); +void ddp_init(void); +int ddp_output(struct mbuf *m, struct socket *so); +int ddp_route(struct mbuf *m, struct route *ro); +struct ddpcb *ddp_search(struct sockaddr_at *, struct sockaddr_at *, + struct at_ifaddr *); + +#endif /* !_NETATALK_AT_EXTERN_HH_ */ diff --git a/freebsd/netatalk/at_proto.c b/freebsd/netatalk/at_proto.c new file mode 100644 index 00000000..cc7902b0 --- /dev/null +++ b/freebsd/netatalk/at_proto.c @@ -0,0 +1,66 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Copyright (c) 1990, 1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + * + * $FreeBSD$ + */ + +#include <freebsd/sys/param.h> +#include <freebsd/sys/protosw.h> +#include <freebsd/sys/domain.h> +#include <freebsd/sys/socket.h> + +#include <freebsd/sys/kernel.h> + +#include <freebsd/net/route.h> + +#include <freebsd/netatalk/at.h> +#include <freebsd/netatalk/ddp_var.h> +#include <freebsd/netatalk/at_extern.h> + +static struct domain atalkdomain; + +static struct protosw atalksw[] = { + { + /* Identifiers */ + .pr_type = SOCK_DGRAM, + .pr_domain = &atalkdomain, + .pr_protocol = ATPROTO_DDP, + .pr_flags = PR_ATOMIC|PR_ADDR, + .pr_output = ddp_output, + .pr_init = ddp_init, + .pr_usrreqs = &ddp_usrreqs, + }, +}; + +static struct domain atalkdomain = { + .dom_family = AF_APPLETALK, + .dom_name = "appletalk", + .dom_protosw = atalksw, + .dom_protoswNPROTOSW = &atalksw[sizeof(atalksw)/sizeof(atalksw[0])], + .dom_rtattach = at_inithead, + .dom_rtoffset = offsetof(struct sockaddr_at, sat_addr) << 3, + .dom_maxrtkey = sizeof(struct sockaddr_at), +}; + +DOMAIN_SET(atalk); diff --git a/freebsd/netatalk/at_rmx.c b/freebsd/netatalk/at_rmx.c new file mode 100644 index 00000000..54272ad7 --- /dev/null +++ b/freebsd/netatalk/at_rmx.c @@ -0,0 +1,119 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Copyright 1994, 1995 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * at_rmx.c,v 1.13 1995/05/30 08:09:31 rgrimes Exp + * $FreeBSD$ + */ + +/* This code generates debugging traces to the radix code. */ + +#include <freebsd/sys/param.h> +#include <freebsd/sys/systm.h> +#include <freebsd/sys/socket.h> + +#include <freebsd/net/route.h> + +int at_inithead(void **head, int off); + +#if 0 +#define HEXBUF_LEN 256 + +static const char * +prsockaddr(void *v, char *hexbuf) +{ + char *bp = &hexbuf[0]; + u_char *cp = v; + + if (v != NULL) { + int len = *cp; + u_char *cplim = cp + len; + + /* return: "(len) hexdump" */ + + bp += sprintf(bp, "(%d)", len); + for (cp++; cp < cplim && bp < hexbuf + (HEXBUF_LEN - 4); + cp++) { + *bp++ = "0123456789abcdef"[*cp / 16]; + *bp++ = "0123456789abcdef"[*cp % 16]; + } + } else + bp+= sprintf(bp, "null"); + *bp = '\0'; + return (hexbuf); +} +#endif + +static struct radix_node * +at_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, + struct radix_node *treenodes) +{ + + return (rn_addroute(v_arg, n_arg, head, treenodes)); +} + +static struct radix_node * +at_matroute(void *v_arg, struct radix_node_head *head) +{ + + return (rn_match(v_arg, head)); +} + +static struct radix_node * +at_lookup(void *v_arg, void *m_arg, struct radix_node_head *head) +{ + + return (rn_lookup(v_arg, m_arg, head)); +} + +static struct radix_node * +at_delroute(void *v_arg, void *netmask_arg, struct radix_node_head *head) +{ + + return (rn_delete(v_arg, netmask_arg, head)); +} + +/* + * Initialize our routing tree with debugging hooks. + */ +int +at_inithead(void **head, int off) +{ + struct radix_node_head *rnh; + + if (!rn_inithead(head, off)) + return (0); + + rnh = *head; + rnh->rnh_addaddr = at_addroute; + rnh->rnh_deladdr = at_delroute; + rnh->rnh_matchaddr = at_matroute; + rnh->rnh_lookup = at_lookup; + return (1); +} diff --git a/freebsd/netatalk/at_var.h b/freebsd/netatalk/at_var.h new file mode 100644 index 00000000..ead90fb1 --- /dev/null +++ b/freebsd/netatalk/at_var.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 1990, 1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + * + * $FreeBSD$ + */ + +#ifndef _NETATALK_AT_VAR_HH_ +#define _NETATALK_AT_VAR_HH_ + +/* + * For phase2, we need to keep not only our address on an interface, but also + * the legal networks on the interface. + */ +struct at_ifaddr { + struct ifaddr aa_ifa; + struct sockaddr_at aa_addr; + struct sockaddr_at aa_broadaddr; + struct sockaddr_at aa_netmask; + int aa_flags; + u_short aa_firstnet; + u_short aa_lastnet; + int aa_probcnt; + struct callout aa_callout; + TAILQ_ENTRY(at_ifaddr) aa_link; +}; +#define aa_ifp aa_ifa.ifa_ifp +#define aa_dstaddr aa_broadaddr; + +TAILQ_HEAD(at_ifaddrhead, at_ifaddr); + +struct at_aliasreq { + char ifra_name[IFNAMSIZ]; + struct sockaddr_at ifra_addr; + struct sockaddr_at ifra_broadaddr; + struct sockaddr_at ifra_mask; +}; +#define ifra_dstaddr ifra_broadaddr + +#define AA_SAT(aa) (&(aa->aa_addr)) +#define satosat(sa) ((struct sockaddr_at *)(sa)) + +#define AFA_ROUTE 0x0001 +#define AFA_PROBING 0x0002 +#define AFA_PHASE2 0x0004 + +#ifdef _KERNEL +extern struct rwlock at_ifaddr_rw; +extern struct at_ifaddrhead at_ifaddrhead; + +#define AT_IFADDR_LOCK_INIT() rw_init(&at_ifaddr_rw, "at_ifaddr_rw") +#define AT_IFADDR_LOCK_ASSERT() rw_assert(&at_ifaddr_rw, RA_LOCKED) +#define AT_IFADDR_RLOCK() rw_rlock(&at_ifaddr_rw) +#define AT_IFADDR_RUNLOCK() rw_runlock(&at_ifaddr_rw) +#define AT_IFADDR_WLOCK() rw_wlock(&at_ifaddr_rw) +#define AT_IFADDR_WUNLOCK() rw_wunlock(&at_ifaddr_rw) +#endif + +#endif /* _NETATALK_AT_VAR_HH_ */ diff --git a/freebsd/netatalk/ddp.h b/freebsd/netatalk/ddp.h new file mode 100644 index 00000000..f954b080 --- /dev/null +++ b/freebsd/netatalk/ddp.h @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 1990, 1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + * + * $FreeBSD$ + */ + +#ifndef _NETATALK_DDP_HH_ +#define _NETATALK_DDP_HH_ + +/*- + * <-1byte(8bits) -> + * +---------------+ + * | 0 | hopc |len| + * +---------------+ + * | len (cont) | + * +---------------+ + * | | + * +- DDP csum -+ + * | | + * +---------------+ + * | | + * +- Dest NET -+ + * | | + * +---------------+ + * | | + * +- Src NET -+ + * | | + * +---------------+ + * | Dest NODE | + * +---------------+ + * | Src NODE | + * +---------------+ + * | Dest PORT | + * +---------------+ + * | Src PORT | + * +---------------+ + * + * On Apples, there is also a ddp_type field, after src_port. However, under + * this unix implementation, user level processes need to be able to set the + * ddp_type. In later revisions, the ddp_type may only be available in a + * raw_appletalk interface. + */ + +struct elaphdr { + u_char el_dnode; + u_char el_snode; + u_char el_type; +} __packed; + +#define SZ_ELAPHDR 3 + +#define ELAP_DDPSHORT 0x01 +#define ELAP_DDPEXTEND 0x02 + +/* + * Extended DDP header. Includes sickness for dealing with arbitrary + * bitfields on a little-endian arch. + */ +struct ddpehdr { + union { + struct { +#if BYTE_ORDER == BIG_ENDIAN + unsigned dub_pad:2; + unsigned dub_hops:4; + unsigned dub_len:10; + unsigned dub_sum:16; +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned dub_sum:16; + unsigned dub_len:10; + unsigned dub_hops:4; + unsigned dub_pad:2; +#endif + } __packed du_bits; + unsigned du_bytes; + } deh_u; + u_short deh_dnet; + u_short deh_snet; + u_char deh_dnode; + u_char deh_snode; + u_char deh_dport; + u_char deh_sport; +} __packed; +#define deh_pad deh_u.du_bits.dub_pad +#define deh_hops deh_u.du_bits.dub_hops +#define deh_len deh_u.du_bits.dub_len +#define deh_sum deh_u.du_bits.dub_sum +#define deh_bytes deh_u.du_bytes + +#define DDP_MAXHOPS 15 + +struct ddpshdr { + union { + struct { +#if BYTE_ORDER == BIG_ENDIAN + unsigned dub_pad:6; + unsigned dub_len:10; + unsigned dub_dport:8; + unsigned dub_sport:8; +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned dub_sport:8; + unsigned dub_dport:8; + unsigned dub_len:10; + unsigned dub_pad:6; +#endif + } __packed du_bits; + unsigned du_bytes; + } dsh_u; +} __packed; + +#define dsh_pad dsh_u.du_bits.dub_pad +#define dsh_len dsh_u.du_bits.dub_len +#define dsh_dport dsh_u.du_bits.dub_dport +#define dsh_sport dsh_u.du_bits.dub_sport +#define dsh_bytes dsh_u.du_bytes + +#endif /* _NETATALK_DDP_HH_ */ diff --git a/freebsd/netatalk/ddp_input.c b/freebsd/netatalk/ddp_input.c new file mode 100644 index 00000000..64eaac7d --- /dev/null +++ b/freebsd/netatalk/ddp_input.c @@ -0,0 +1,442 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Copyright (c) 2004-2009 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ + */ + +#include <freebsd/sys/param.h> +#include <freebsd/sys/kernel.h> +#include <freebsd/sys/lock.h> +#include <freebsd/sys/mbuf.h> +#include <freebsd/sys/signalvar.h> +#include <freebsd/sys/socket.h> +#include <freebsd/sys/socketvar.h> +#include <freebsd/sys/sx.h> +#include <freebsd/sys/systm.h> +#include <freebsd/net/if.h> +#include <freebsd/net/route.h> + +#include <freebsd/netatalk/at.h> +#include <freebsd/netatalk/at_var.h> +#include <freebsd/netatalk/ddp.h> +#include <freebsd/netatalk/ddp_var.h> +#include <freebsd/netatalk/ddp_pcb.h> +#include <freebsd/netatalk/at_extern.h> + +#include <freebsd/security/mac/mac_framework.h> + +static volatile int ddp_forward = 1; +static volatile int ddp_firewall = 0; +static struct ddpstat ddpstat; + +static struct route forwro; + +static void ddp_input(struct mbuf *, struct ifnet *, struct elaphdr *, int); + +/* + * Could probably merge these two code segments a little better... + */ +void +at2intr(struct mbuf *m) +{ + + /* + * Phase 2 packet handling . + */ + ddp_input(m, m->m_pkthdr.rcvif, NULL, 2); +} + +void +at1intr(struct mbuf *m) +{ + struct elaphdr *elhp, elh; + + /* + * Phase 1 packet handling + */ + if (m->m_len < SZ_ELAPHDR && ((m = m_pullup(m, SZ_ELAPHDR)) == + NULL)) { + ddpstat.ddps_tooshort++; + return; + } + + /* + * This seems a little dubious, but I don't know phase 1 so leave it. + */ + elhp = mtod(m, struct elaphdr *); + m_adj(m, SZ_ELAPHDR); + + if (elhp->el_type != ELAP_DDPEXTEND) { + bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR); + ddp_input(m, m->m_pkthdr.rcvif, &elh, 1); + } else + ddp_input(m, m->m_pkthdr.rcvif, NULL, 1); +} + +static void +ddp_input(struct mbuf *m, struct ifnet *ifp, struct elaphdr *elh, int phase) +{ + struct sockaddr_at from, to; + struct ddpshdr *dsh, ddps; + struct at_ifaddr *aa; + struct ddpehdr *deh = NULL, ddpe; + struct ddpcb *ddp; + int dlen, mlen; + u_short cksum = 0; + + bzero((caddr_t)&from, sizeof(struct sockaddr_at)); + bzero((caddr_t)&to, sizeof(struct sockaddr_at)); + if (elh != NULL) { + /* + * Extract the information in the short header. Network + * information is defaulted to ATADDR_ANYNET and node + * information comes from the elh info. We must be phase 1. + */ + ddpstat.ddps_short++; + + if (m->m_len < sizeof(struct ddpshdr) && + ((m = m_pullup(m, sizeof(struct ddpshdr))) == NULL)) { + ddpstat.ddps_tooshort++; + return; + } + + dsh = mtod(m, struct ddpshdr *); + bcopy((caddr_t)dsh, (caddr_t)&ddps, sizeof(struct ddpshdr)); + ddps.dsh_bytes = ntohl(ddps.dsh_bytes); + dlen = ddps.dsh_len; + + to.sat_addr.s_net = ATADDR_ANYNET; + to.sat_addr.s_node = elh->el_dnode; + to.sat_port = ddps.dsh_dport; + from.sat_addr.s_net = ATADDR_ANYNET; + from.sat_addr.s_node = elh->el_snode; + from.sat_port = ddps.dsh_sport; + + /* + * Make sure that we point to the phase1 ifaddr info and that + * it's valid for this packet. + */ + AT_IFADDR_RLOCK(); + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if ((aa->aa_ifp == ifp) + && ((aa->aa_flags & AFA_PHASE2) == 0) + && ((to.sat_addr.s_node == + AA_SAT(aa)->sat_addr.s_node) || + (to.sat_addr.s_node == ATADDR_BCAST))) + break; + } + /* + * maybe we got a broadcast not meant for us.. ditch it. + */ + if (aa == NULL) { + AT_IFADDR_RUNLOCK(); + m_freem(m); + return; + } + } else { + /* + * There was no 'elh' passed on. This could still be either + * phase1 or phase2. We have a long header, but we may be + * running on a phase 1 net. Extract out all the info + * regarding this packet's src & dst. + */ + ddpstat.ddps_long++; + + if (m->m_len < sizeof(struct ddpehdr) && + ((m = m_pullup(m, sizeof(struct ddpehdr))) == NULL)) { + AT_IFADDR_RUNLOCK(); + ddpstat.ddps_tooshort++; + return; + } + + deh = mtod(m, struct ddpehdr *); + bcopy((caddr_t)deh, (caddr_t)&ddpe, sizeof(struct ddpehdr)); + ddpe.deh_bytes = ntohl(ddpe.deh_bytes); + dlen = ddpe.deh_len; + + if ((cksum = ddpe.deh_sum) == 0) + ddpstat.ddps_nosum++; + + from.sat_addr.s_net = ddpe.deh_snet; + from.sat_addr.s_node = ddpe.deh_snode; + from.sat_port = ddpe.deh_sport; + to.sat_addr.s_net = ddpe.deh_dnet; + to.sat_addr.s_node = ddpe.deh_dnode; + to.sat_port = ddpe.deh_dport; + + AT_IFADDR_RLOCK(); + if (to.sat_addr.s_net == ATADDR_ANYNET) { + /* + * The TO address doesn't specify a net, so by + * definition it's for this net. Try find ifaddr + * info with the right phase, the right interface, + * and either to our node, a broadcast, or looped + * back (though that SHOULD be covered in the other + * cases). + * + * XXX If we have multiple interfaces, then the first + * with this node number will match (which may NOT be + * what we want, but it's probably safe in 99.999% of + * cases. + */ + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if (phase == 1 && (aa->aa_flags & + AFA_PHASE2)) + continue; + if (phase == 2 && (aa->aa_flags & + AFA_PHASE2) == 0) + continue; + if ((aa->aa_ifp == ifp) && + ((to.sat_addr.s_node == + AA_SAT(aa)->sat_addr.s_node) || + (to.sat_addr.s_node == ATADDR_BCAST) || + (ifp->if_flags & IFF_LOOPBACK))) + break; + } + } else { + /* + * A destination network was given. We just try to + * find which ifaddr info matches it. + */ + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + /* + * This is a kludge. Accept packets that are + * for any router on a local netrange. + */ + if (to.sat_addr.s_net == aa->aa_firstnet && + to.sat_addr.s_node == 0) + break; + /* + * Don't use ifaddr info for which we are + * totally outside the netrange, and it's not + * a startup packet. Startup packets are + * always implicitly allowed on to the next + * test. + */ + if (((ntohs(to.sat_addr.s_net) < + ntohs(aa->aa_firstnet)) || + (ntohs(to.sat_addr.s_net) > + ntohs(aa->aa_lastnet))) && + ((ntohs(to.sat_addr.s_net) < 0xff00) || + (ntohs(to.sat_addr.s_net) > 0xfffe))) + continue; + + /* + * Don't record a match either if we just + * don't have a match in the node address. + * This can have if the interface is in + * promiscuous mode for example. + */ + if ((to.sat_addr.s_node != + AA_SAT(aa)->sat_addr.s_node) && + (to.sat_addr.s_node != ATADDR_BCAST)) + continue; + break; + } + } + } + if (aa != NULL) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + + /* + * Adjust the length, removing any padding that may have been added + * at a link layer. We do this before we attempt to forward a + * packet, possibly on a different media. + */ + mlen = m->m_pkthdr.len; + if (mlen < dlen) { + ddpstat.ddps_toosmall++; + goto out; + } + if (mlen > dlen) + m_adj(m, dlen - mlen); + + /* + * If it isn't for a net on any of our interfaces, or it IS for a net + * on a different interface than it came in on, (and it is not looped + * back) then consider if we should forward it. As we are not really + * a router this is a bit cheeky, but it may be useful some day. + */ + if ((aa == NULL) || ((to.sat_addr.s_node == ATADDR_BCAST) && + (aa->aa_ifp != ifp) && ((ifp->if_flags & IFF_LOOPBACK) == 0))) { + /* + * If we've explicitly disabled it, don't route anything. + */ + if (ddp_forward == 0) + goto out; + + /* + * If the cached forwarding route is still valid, use it. + * + * XXXRW: Access to the cached route may not be properly + * synchronized for parallel input handling. + */ + if (forwro.ro_rt && + (satosat(&forwro.ro_dst)->sat_addr.s_net != + to.sat_addr.s_net || + satosat(&forwro.ro_dst)->sat_addr.s_node != + to.sat_addr.s_node)) { + RTFREE(forwro.ro_rt); + forwro.ro_rt = NULL; + } + + /* + * If we don't have a cached one (any more) or it's useless, + * then get a new route. + * + * XXX this could cause a 'route leak'. Check this! + */ + if (forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp == NULL) { + forwro.ro_dst.sa_len = sizeof(struct sockaddr_at); + forwro.ro_dst.sa_family = AF_APPLETALK; + satosat(&forwro.ro_dst)->sat_addr.s_net = + to.sat_addr.s_net; + satosat(&forwro.ro_dst)->sat_addr.s_node = + to.sat_addr.s_node; + rtalloc(&forwro); + } + + /* + * If it's not going to get there on this hop, and it's + * already done too many hops, then throw it away. + */ + if ((to.sat_addr.s_net != + satosat(&forwro.ro_dst)->sat_addr.s_net) && + (ddpe.deh_hops == DDP_MAXHOPS)) + goto out; + + /* + * A ddp router might use the same interface to forward the + * packet, which this would not effect. Don't allow packets + * to cross from one interface to another however. + */ + if (ddp_firewall && ((forwro.ro_rt == NULL) || + (forwro.ro_rt->rt_ifp != ifp))) + goto out; + + /* + * Adjust the header. If it was a short header then it would + * have not gotten here, so we can assume there is room to + * drop the header in. + * + * XXX what about promiscuous mode, etc... + */ + ddpe.deh_hops++; + ddpe.deh_bytes = htonl(ddpe.deh_bytes); + /* XXX deh? */ + bcopy((caddr_t)&ddpe, (caddr_t)deh, sizeof(u_short)); + if (ddp_route(m, &forwro)) + ddpstat.ddps_cantforward++; + else + ddpstat.ddps_forward++; + if (aa != NULL) + ifa_free(&aa->aa_ifa); + return; + } + + /* + * It was for us, and we have an ifaddr to use with it. + */ + from.sat_len = sizeof(struct sockaddr_at); + from.sat_family = AF_APPLETALK; + + /* + * We are no longer interested in the link layer so cut it off. + */ + if (elh == NULL) { + if (ddp_cksum && cksum && cksum != + at_cksum(m, sizeof(int))) { + ddpstat.ddps_badsum++; + goto out; + } + m_adj(m, sizeof(struct ddpehdr)); + } else + m_adj(m, sizeof(struct ddpshdr)); + + /* + * Search for ddp protocol control blocks that match these addresses. + */ + DDP_LIST_SLOCK(); + if ((ddp = ddp_search(&from, &to, aa)) == NULL) + goto out_unlock; + +#ifdef MAC + if (mac_socket_check_deliver(ddp->ddp_socket, m) != 0) + goto out_unlock; +#endif + + /* + * If we found one, deliver the packet to the socket + */ + SOCKBUF_LOCK(&ddp->ddp_socket->so_rcv); + if (sbappendaddr_locked(&ddp->ddp_socket->so_rcv, + (struct sockaddr *)&from, m, NULL) == 0) { + SOCKBUF_UNLOCK(&ddp->ddp_socket->so_rcv); + /* + * If the socket is full (or similar error) dump the packet. + */ + ddpstat.ddps_nosockspace++; + goto out_unlock; + } + + /* + * And wake up whatever might be waiting for it + */ + sorwakeup_locked(ddp->ddp_socket); + m = NULL; +out_unlock: + DDP_LIST_SUNLOCK(); +out: + if (aa != NULL) + ifa_free(&aa->aa_ifa); + if (m != NULL) + m_freem(m); +} diff --git a/freebsd/netatalk/ddp_output.c b/freebsd/netatalk/ddp_output.c new file mode 100644 index 00000000..0bb74123 --- /dev/null +++ b/freebsd/netatalk/ddp_output.c @@ -0,0 +1,249 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Copyright (c) 1990, 1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + */ + +/* $FreeBSD$ */ + +#include <freebsd/sys/param.h> +#include <freebsd/sys/systm.h> +#include <freebsd/sys/mbuf.h> +#include <freebsd/sys/socket.h> +#include <freebsd/sys/socketvar.h> + +#include <freebsd/net/if.h> +#include <freebsd/net/route.h> + +#undef s_net + +#include <freebsd/netatalk/at.h> +#include <freebsd/netatalk/at_var.h> +#include <freebsd/netatalk/ddp.h> +#include <freebsd/netatalk/ddp_var.h> +#include <freebsd/netatalk/at_extern.h> + +#include <freebsd/security/mac/mac_framework.h> + +int ddp_cksum = 1; + +int +ddp_output(struct mbuf *m, struct socket *so) +{ + struct ddpehdr *deh; + struct ddpcb *ddp = sotoddpcb(so); + +#ifdef MAC + mac_socket_create_mbuf(so, m); +#endif + + M_PREPEND(m, sizeof(struct ddpehdr), M_DONTWAIT); + if (m == NULL) + return (ENOBUFS); + + deh = mtod(m, struct ddpehdr *); + deh->deh_pad = 0; + deh->deh_hops = 0; + + deh->deh_len = m->m_pkthdr.len; + + deh->deh_dnet = ddp->ddp_fsat.sat_addr.s_net; + deh->deh_dnode = ddp->ddp_fsat.sat_addr.s_node; + deh->deh_dport = ddp->ddp_fsat.sat_port; + deh->deh_snet = ddp->ddp_lsat.sat_addr.s_net; + deh->deh_snode = ddp->ddp_lsat.sat_addr.s_node; + deh->deh_sport = ddp->ddp_lsat.sat_port; + + /* + * The checksum calculation is done after all of the other bytes have + * been filled in. + */ + if (ddp_cksum) + deh->deh_sum = at_cksum(m, sizeof(int)); + else + deh->deh_sum = 0; + deh->deh_bytes = htonl(deh->deh_bytes); + +#ifdef NETATALK_DEBUG + printf ("ddp_output: from %d.%d:%d to %d.%d:%d\n", + ntohs(deh->deh_snet), deh->deh_snode, deh->deh_sport, + ntohs(deh->deh_dnet), deh->deh_dnode, deh->deh_dport); +#endif + return (ddp_route(m, &ddp->ddp_route)); +} + +u_short +at_cksum(struct mbuf *m, int skip) +{ + u_char *data, *end; + u_long cksum = 0; + + for (; m; m = m->m_next) { + for (data = mtod(m, u_char *), end = data + m->m_len; + data < end; data++) { + if (skip) { + skip--; + continue; + } + cksum = (cksum + *data) << 1; + if (cksum & 0x00010000) + cksum++; + cksum &= 0x0000ffff; + } + } + + if (cksum == 0) + cksum = 0x0000ffff; + return ((u_short)cksum); +} + +int +ddp_route(struct mbuf *m, struct route *ro) +{ + struct sockaddr_at gate; + struct elaphdr *elh; + struct mbuf *m0; + struct at_ifaddr *aa = NULL; + struct ifnet *ifp = NULL; + u_short net; + +#if 0 + /* Check for net zero, node zero ("myself") */ + if (satosat(&ro->ro_dst)->sat_addr.s_net == ATADDR_ANYNET + && satosat(&ro->ro_dst)->sat_addr.s_node == ATADDR_ANYNODE) { + /* Find the loopback interface */ + } +#endif + + /* + * If we have a route, find the ifa that refers to this route. I.e + * the ifa used to get to the gateway. + */ + if ((ro->ro_rt == NULL) || (ro->ro_rt->rt_ifa == NULL) || + ((ifp = ro->ro_rt->rt_ifa->ifa_ifp) == NULL)) + rtalloc(ro); + if ((ro->ro_rt != NULL) && (ro->ro_rt->rt_ifa) && + (ifp = ro->ro_rt->rt_ifa->ifa_ifp)) { + net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net); + AT_IFADDR_RLOCK(); + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if (((net == 0) || (aa->aa_ifp == ifp)) && + net >= ntohs(aa->aa_firstnet) && + net <= ntohs(aa->aa_lastnet)) + break; + } + if (aa != NULL) + ifa_ref(&aa->aa_ifa); + AT_IFADDR_RUNLOCK(); + } else { + m_freem(m); +#ifdef NETATALK_DEBUG + if (ro->ro_rt == NULL) + printf ("ddp_route: no ro_rt.\n"); + else if (ro->ro_rt->rt_ifa == NULL) + printf ("ddp_route: no ro_rt->rt_ifa\n"); + else + printf ("ddp_route: no ro_rt->rt_ifa->ifa_ifp\n"); +#endif + return (ENETUNREACH); + } + + if (aa == NULL) { +#ifdef NETATALK_DEBUG + printf("ddp_route: no atalk address found for %s\n", + ifp->if_xname); +#endif + m_freem(m); + return (ENETUNREACH); + } + + /* + * If the destination address is on a directly attached node use + * that, else use the official gateway. + */ + if (ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) >= + ntohs(aa->aa_firstnet) && + ntohs(satosat(&ro->ro_dst)->sat_addr.s_net) <= + ntohs(aa->aa_lastnet)) + gate = *satosat(&ro->ro_dst); + else + gate = *satosat(ro->ro_rt->rt_gateway); + + /* + * There are several places in the kernel where data is added to an + * mbuf without ensuring that the mbuf pointer is aligned. This is + * bad for transition routing, since phase 1 and phase 2 packets end + * up poorly aligned due to the three byte elap header. + * + * XXXRW: kern/4184 suggests that an m_pullup() of (m) should take + * place here to address possible alignment issues. + * + * XXXRW: This appears not to handle M_PKTHDR properly, as it doesn't + * move the existing header from the old packet to the new one. + * Posibly should call M_MOVE_PKTHDR()? This would also allow + * removing mac_mbuf_copy(). + */ + if (!(aa->aa_flags & AFA_PHASE2)) { + MGET(m0, M_DONTWAIT, MT_DATA); + if (m0 == NULL) { + ifa_free(&aa->aa_ifa); + m_freem(m); + printf("ddp_route: no buffers\n"); + return (ENOBUFS); + } +#ifdef MAC + mac_mbuf_copy(m, m0); +#endif + m0->m_next = m; + /* XXX perhaps we ought to align the header? */ + m0->m_len = SZ_ELAPHDR; + m = m0; + + elh = mtod(m, struct elaphdr *); + elh->el_snode = satosat(&aa->aa_addr)->sat_addr.s_node; + elh->el_type = ELAP_DDPEXTEND; + elh->el_dnode = gate.sat_addr.s_node; + } + ro->ro_rt->rt_use++; + +#ifdef NETATALK_DEBUG + printf ("ddp_route: from %d.%d to %d.%d, via %d.%d (%s)\n", + ntohs(satosat(&aa->aa_addr)->sat_addr.s_net), + satosat(&aa->aa_addr)->sat_addr.s_node, + ntohs(satosat(&ro->ro_dst)->sat_addr.s_net), + satosat(&ro->ro_dst)->sat_addr.s_node, + ntohs(gate.sat_addr.s_net), gate.sat_addr.s_node, ifp->if_xname); +#endif + + /* Short-circuit the output if we're sending this to ourself. */ + if ((satosat(&aa->aa_addr)->sat_addr.s_net == + satosat(&ro->ro_dst)->sat_addr.s_net) && + (satosat(&aa->aa_addr)->sat_addr.s_node == + satosat(&ro->ro_dst)->sat_addr.s_node)) { + ifa_free(&aa->aa_ifa); + return (if_simloop(ifp, m, gate.sat_family, 0)); + } + ifa_free(&aa->aa_ifa); + + /* XXX */ + return ((*ifp->if_output)(ifp, m, (struct sockaddr *)&gate, NULL)); +} diff --git a/freebsd/netatalk/ddp_pcb.c b/freebsd/netatalk/ddp_pcb.c new file mode 100644 index 00000000..4faeb092 --- /dev/null +++ b/freebsd/netatalk/ddp_pcb.c @@ -0,0 +1,418 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Copyright (c) 2004-2009 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * $FreeBSD$ + */ + +#include <freebsd/sys/param.h> +#include <freebsd/sys/systm.h> +#include <freebsd/sys/malloc.h> +#include <freebsd/sys/mbuf.h> +#include <freebsd/sys/priv.h> +#include <freebsd/sys/socket.h> +#include <freebsd/sys/socketvar.h> +#include <freebsd/sys/protosw.h> +#include <freebsd/net/if.h> +#include <freebsd/net/route.h> +#include <freebsd/net/netisr.h> + +#include <freebsd/netatalk/at.h> +#include <freebsd/netatalk/at_var.h> +#include <freebsd/netatalk/ddp_var.h> +#include <freebsd/netatalk/ddp_pcb.h> +#include <freebsd/netatalk/at_extern.h> + +struct mtx ddp_list_mtx; +static struct ddpcb *ddp_ports[ATPORT_LAST]; +struct ddpcb *ddpcb_list = NULL; + +void +at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr) +{ + + /* + * Prevent modification of ddp during copy of addr. + */ + DDP_LOCK_ASSERT(ddp); + *addr = sodupsockaddr((struct sockaddr *)&ddp->ddp_lsat, M_NOWAIT); +} + +int +at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) +{ + struct sockaddr_at lsat, *sat; + struct at_ifaddr *aa; + struct ddpcb *ddpp; + + /* + * We read and write both the ddp passed in, and also ddp_ports. + */ + DDP_LIST_XLOCK_ASSERT(); + DDP_LOCK_ASSERT(ddp); + + /* + * Shouldn't be bound. + */ + if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) + return (EINVAL); + + /* + * Validate passed address. + */ + aa = NULL; + if (addr != NULL) { + sat = (struct sockaddr_at *)addr; + if (sat->sat_family != AF_APPLETALK) + return (EAFNOSUPPORT); + + if (sat->sat_addr.s_node != ATADDR_ANYNODE || + sat->sat_addr.s_net != ATADDR_ANYNET) { + AT_IFADDR_RLOCK(); + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if ((sat->sat_addr.s_net == + AA_SAT(aa)->sat_addr.s_net) && + (sat->sat_addr.s_node == + AA_SAT(aa)->sat_addr.s_node)) + break; + } + AT_IFADDR_RUNLOCK(); + if (aa == NULL) + return (EADDRNOTAVAIL); + } + + if (sat->sat_port != ATADDR_ANYPORT) { + if (sat->sat_port < ATPORT_FIRST || + sat->sat_port >= ATPORT_LAST) + return (EINVAL); + if (sat->sat_port < ATPORT_RESERVED && + priv_check(td, PRIV_NETATALK_RESERVEDPORT)) + return (EACCES); + } + } else { + bzero((caddr_t)&lsat, sizeof(struct sockaddr_at)); + lsat.sat_len = sizeof(struct sockaddr_at); + lsat.sat_addr.s_node = ATADDR_ANYNODE; + lsat.sat_addr.s_net = ATADDR_ANYNET; + lsat.sat_family = AF_APPLETALK; + sat = &lsat; + } + + if (sat->sat_addr.s_node == ATADDR_ANYNODE && + sat->sat_addr.s_net == ATADDR_ANYNET) { + AT_IFADDR_RLOCK(); + if (TAILQ_EMPTY(&at_ifaddrhead)) { + AT_IFADDR_RUNLOCK(); + return (EADDRNOTAVAIL); + } + sat->sat_addr = AA_SAT(TAILQ_FIRST(&at_ifaddrhead))->sat_addr; + AT_IFADDR_RUNLOCK(); + } + ddp->ddp_lsat = *sat; + + /* + * Choose port. + */ + if (sat->sat_port == ATADDR_ANYPORT) { + for (sat->sat_port = ATPORT_RESERVED; + sat->sat_port < ATPORT_LAST; sat->sat_port++) { + if (ddp_ports[sat->sat_port - 1] == NULL) + break; + } + if (sat->sat_port == ATPORT_LAST) + return (EADDRNOTAVAIL); + ddp->ddp_lsat.sat_port = sat->sat_port; + ddp_ports[sat->sat_port - 1] = ddp; + } else { + for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp; + ddpp = ddpp->ddp_pnext) { + if (ddpp->ddp_lsat.sat_addr.s_net == + sat->sat_addr.s_net && + ddpp->ddp_lsat.sat_addr.s_node == + sat->sat_addr.s_node) + break; + } + if (ddpp != NULL) + return (EADDRINUSE); + ddp->ddp_pnext = ddp_ports[sat->sat_port - 1]; + ddp_ports[sat->sat_port - 1] = ddp; + if (ddp->ddp_pnext != NULL) + ddp->ddp_pnext->ddp_pprev = ddp; + } + + return (0); +} + +int +at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) +{ + struct sockaddr_at *sat = (struct sockaddr_at *)addr; + struct route *ro; + struct at_ifaddr *aa = NULL; + struct ifnet *ifp; + u_short hintnet = 0, net; + + DDP_LIST_XLOCK_ASSERT(); + DDP_LOCK_ASSERT(ddp); + + if (sat->sat_family != AF_APPLETALK) + return (EAFNOSUPPORT); + + /* + * Under phase 2, network 0 means "the network". We take "the + * network" to mean the network the control block is bound to. If + * the control block is not bound, there is an error. + */ + if (sat->sat_addr.s_net == ATADDR_ANYNET && + sat->sat_addr.s_node != ATADDR_ANYNODE) { + if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) + return (EADDRNOTAVAIL); + hintnet = ddp->ddp_lsat.sat_addr.s_net; + } + + ro = &ddp->ddp_route; + /* + * If we've got an old route for this pcb, check that it is valid. + * If we've changed our address, we may have an old "good looking" + * route here. Attempt to detect it. + */ + if (ro->ro_rt) { + if (hintnet) + net = hintnet; + else + net = sat->sat_addr.s_net; + aa = NULL; + AT_IFADDR_RLOCK(); + if ((ifp = ro->ro_rt->rt_ifp) != NULL) { + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if (aa->aa_ifp == ifp && + ntohs(net) >= ntohs(aa->aa_firstnet) && + ntohs(net) <= ntohs(aa->aa_lastnet)) + break; + } + } + if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net != + (hintnet ? hintnet : sat->sat_addr.s_net) || + satosat(&ro->ro_dst)->sat_addr.s_node != + sat->sat_addr.s_node)) { + RTFREE(ro->ro_rt); + ro->ro_rt = NULL; + } + AT_IFADDR_RUNLOCK(); + } + + /* + * If we've got no route for this interface, try to find one. + */ + if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { + ro->ro_dst.sa_len = sizeof(struct sockaddr_at); + ro->ro_dst.sa_family = AF_APPLETALK; + if (hintnet) + satosat(&ro->ro_dst)->sat_addr.s_net = hintnet; + else + satosat(&ro->ro_dst)->sat_addr.s_net = + sat->sat_addr.s_net; + satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node; + rtalloc(ro); + } + + /* + * Make sure any route that we have has a valid interface. + */ + aa = NULL; + if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { + AT_IFADDR_RLOCK(); + TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { + if (aa->aa_ifp == ifp) + break; + } + AT_IFADDR_RUNLOCK(); + } + if (aa == NULL) + return (ENETUNREACH); + + ddp->ddp_fsat = *sat; + if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) + return (at_pcbsetaddr(ddp, NULL, td)); + return (0); +} + +void +at_pcbdisconnect(struct ddpcb *ddp) +{ + + DDP_LOCK_ASSERT(ddp); + + ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; + ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; + ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; +} + +int +at_pcballoc(struct socket *so) +{ + struct ddpcb *ddp; + + DDP_LIST_XLOCK_ASSERT(); + + ddp = malloc(sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO); + if (ddp == NULL) + return (ENOBUFS); + DDP_LOCK_INIT(ddp); + ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; + + ddp->ddp_socket = so; + so->so_pcb = (caddr_t)ddp; + + ddp->ddp_next = ddpcb_list; + ddp->ddp_prev = NULL; + ddp->ddp_pprev = NULL; + ddp->ddp_pnext = NULL; + if (ddpcb_list != NULL) + ddpcb_list->ddp_prev = ddp; + ddpcb_list = ddp; + return(0); +} + +void +at_pcbdetach(struct socket *so, struct ddpcb *ddp) +{ + + /* + * We modify ddp, ddp_ports, and the global list. + */ + DDP_LIST_XLOCK_ASSERT(); + DDP_LOCK_ASSERT(ddp); + KASSERT(so->so_pcb != NULL, ("at_pcbdetach: so_pcb == NULL")); + + so->so_pcb = NULL; + + /* Remove ddp from ddp_ports list. */ + if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && + ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) { + if (ddp->ddp_pprev != NULL) + ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; + else + ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext; + if (ddp->ddp_pnext != NULL) + ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; + } + + if (ddp->ddp_route.ro_rt) + RTFREE(ddp->ddp_route.ro_rt); + + if (ddp->ddp_prev) + ddp->ddp_prev->ddp_next = ddp->ddp_next; + else + ddpcb_list = ddp->ddp_next; + if (ddp->ddp_next) + ddp->ddp_next->ddp_prev = ddp->ddp_prev; + DDP_UNLOCK(ddp); + DDP_LOCK_DESTROY(ddp); + free(ddp, M_PCB); +} + +/* + * For the moment, this just find the pcb with the correct local address. In + * the future, this will actually do some real searching, so we can use the + * sender's address to do de-multiplexing on a single port to many sockets + * (pcbs). + */ +struct ddpcb * +ddp_search(struct sockaddr_at *from, struct sockaddr_at *to, + struct at_ifaddr *aa) +{ + struct ddpcb *ddp; + + DDP_LIST_SLOCK_ASSERT(); + + /* + * Check for bad ports. + */ + if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) + return (NULL); + + /* + * Make sure the local address matches the sent address. What about + * the interface? + */ + for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) { + DDP_LOCK(ddp); + /* XXX should we handle 0.YY? */ + /* XXXX.YY to socket on destination interface */ + if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && + to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) { + DDP_UNLOCK(ddp); + break; + } + + /* 0.255 to socket on receiving interface */ + if (to->sat_addr.s_node == ATADDR_BCAST && + (to->sat_addr.s_net == 0 || + to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) && + ddp->ddp_lsat.sat_addr.s_net == + AA_SAT(aa)->sat_addr.s_net) { + DDP_UNLOCK(ddp); + break; + } + + /* XXXX.0 to socket on destination interface */ + if (to->sat_addr.s_net == aa->aa_firstnet && + to->sat_addr.s_node == 0 && + ntohs(ddp->ddp_lsat.sat_addr.s_net) >= + ntohs(aa->aa_firstnet) && + ntohs(ddp->ddp_lsat.sat_addr.s_net) <= + ntohs(aa->aa_lastnet)) { + DDP_UNLOCK(ddp); + break; + } + DDP_UNLOCK(ddp); + } + return (ddp); +} diff --git a/freebsd/netatalk/ddp_pcb.h b/freebsd/netatalk/ddp_pcb.h new file mode 100644 index 00000000..4449c3ae --- /dev/null +++ b/freebsd/netatalk/ddp_pcb.h @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2004 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ + */ + +#ifndef _NETATALK_DDP_PCB_HH_ +#define _NETATALK_DDP_PCB_HH_ + +int at_pcballoc(struct socket *so); +int at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, + struct thread *td); +void at_pcbdetach(struct socket *so, struct ddpcb *ddp); +void at_pcbdisconnect(struct ddpcb *ddp); +int at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, + struct thread *td); +void at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr); + +/* Lock macros for per-pcb locks. */ +#define DDP_LOCK_INIT(ddp) mtx_init(&(ddp)->ddp_mtx, "ddp_mtx", \ + NULL, MTX_DEF) +#define DDP_LOCK_DESTROY(ddp) mtx_destroy(&(ddp)->ddp_mtx) +#define DDP_LOCK(ddp) mtx_lock(&(ddp)->ddp_mtx) +#define DDP_UNLOCK(ddp) mtx_unlock(&(ddp)->ddp_mtx) +#define DDP_LOCK_ASSERT(ddp) mtx_assert(&(ddp)->ddp_mtx, MA_OWNED) + +/* Lock macros for global pcb list lock. */ +#define DDP_LIST_LOCK_INIT() mtx_init(&ddp_list_mtx, "ddp_list_mtx", \ + NULL, MTX_DEF) +#define DDP_LIST_LOCK_DESTROY() mtx_destroy(&ddp_list_mtx) +#define DDP_LIST_XLOCK() mtx_lock(&ddp_list_mtx) +#define DDP_LIST_XUNLOCK() mtx_unlock(&ddp_list_mtx) +#define DDP_LIST_XLOCK_ASSERT() mtx_assert(&ddp_list_mtx, MA_OWNED) +#define DDP_LIST_SLOCK() mtx_lock(&ddp_list_mtx) +#define DDP_LIST_SUNLOCK() mtx_unlock(&ddp_list_mtx) +#define DDP_LIST_SLOCK_ASSERT() mtx_assert(&ddp_list_mtx, MA_OWNED) + +#endif /* !_NETATALK_DDP_PCB_HH_ */ diff --git a/freebsd/netatalk/ddp_usrreq.c b/freebsd/netatalk/ddp_usrreq.c new file mode 100644 index 00000000..1d1990c4 --- /dev/null +++ b/freebsd/netatalk/ddp_usrreq.c @@ -0,0 +1,333 @@ +#include <freebsd/machine/rtems-bsd-config.h> + +/*- + * Copyright (c) 2004-2009 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ + */ + +#include <freebsd/sys/param.h> +#include <freebsd/sys/systm.h> +#include <freebsd/sys/malloc.h> +#include <freebsd/sys/mbuf.h> +#include <freebsd/sys/socket.h> +#include <freebsd/sys/socketvar.h> +#include <freebsd/sys/protosw.h> +#include <freebsd/net/if.h> +#include <freebsd/net/route.h> +#include <freebsd/net/netisr.h> + +#include <freebsd/netatalk/at.h> +#include <freebsd/netatalk/at_var.h> +#include <freebsd/netatalk/ddp_var.h> +#include <freebsd/netatalk/ddp_pcb.h> +#include <freebsd/netatalk/at_extern.h> + +static u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ +static u_long ddp_recvspace = 10 * (587 + sizeof(struct sockaddr_at)); + +static const struct netisr_handler atalk1_nh = { + .nh_name = "atalk1", + .nh_handler = at1intr, + .nh_proto = NETISR_ATALK1, + .nh_policy = NETISR_POLICY_SOURCE, +}; + +static const struct netisr_handler atalk2_nh = { + .nh_name = "atalk2", + .nh_handler = at2intr, + .nh_proto = NETISR_ATALK2, + .nh_policy = NETISR_POLICY_SOURCE, +}; + +static const struct netisr_handler aarp_nh = { + .nh_name = "aarp", + .nh_handler = aarpintr, + .nh_proto = NETISR_AARP, + .nh_policy = NETISR_POLICY_SOURCE, +}; + +static int +ddp_attach(struct socket *so, int proto, struct thread *td) +{ + int error = 0; + + KASSERT(sotoddpcb(so) == NULL, ("ddp_attach: ddp != NULL")); + + /* + * Allocate socket buffer space first so that it's present + * before first use. + */ + error = soreserve(so, ddp_sendspace, ddp_recvspace); + if (error) + return (error); + + DDP_LIST_XLOCK(); + error = at_pcballoc(so); + DDP_LIST_XUNLOCK(); + return (error); +} + +static void +ddp_detach(struct socket *so) +{ + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_detach: ddp == NULL")); + + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + at_pcbdetach(so, ddp); + DDP_LIST_XUNLOCK(); +} + +static int +ddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) +{ + struct ddpcb *ddp; + int error = 0; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL")); + + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + error = at_pcbsetaddr(ddp, nam, td); + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); + return (error); +} + +static int +ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) +{ + struct ddpcb *ddp; + int error = 0; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_connect: ddp == NULL")); + + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); + return (EISCONN); + } + + error = at_pcbconnect( ddp, nam, td ); + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); + if (error == 0) + soisconnected(so); + return (error); +} + +static int +ddp_disconnect(struct socket *so) +{ + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL")); + + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) { + DDP_UNLOCK(ddp); + return (ENOTCONN); + } + + at_pcbdisconnect(ddp); + ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; + DDP_UNLOCK(ddp); + soisdisconnected(so); + return (0); +} + +static int +ddp_shutdown(struct socket *so) +{ + + KASSERT(sotoddpcb(so) != NULL, ("ddp_shutdown: ddp == NULL")); + + socantsendmore(so); + return (0); +} + +static int +ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, + struct mbuf *control, struct thread *td) +{ + struct ddpcb *ddp; + int error = 0; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_send: ddp == NULL")); + + if (control && control->m_len) + return (EINVAL); + + if (addr != NULL) { + DDP_LIST_XLOCK(); + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { + error = EISCONN; + goto out; + } + + error = at_pcbconnect(ddp, addr, td); + if (error == 0) { + error = ddp_output(m, so); + at_pcbdisconnect(ddp); + } +out: + DDP_UNLOCK(ddp); + DDP_LIST_XUNLOCK(); + } else { + DDP_LOCK(ddp); + if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) + error = ENOTCONN; + else + error = ddp_output(m, so); + DDP_UNLOCK(ddp); + } + return (error); +} + +/* + * XXXRW: This is never called because we only invoke abort on stream + * protocols. + */ +static void +ddp_abort(struct socket *so) +{ + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL")); + + DDP_LOCK(ddp); + at_pcbdisconnect(ddp); + DDP_UNLOCK(ddp); + soisdisconnected(so); +} + +static void +ddp_close(struct socket *so) +{ + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("ddp_close: ddp == NULL")); + + DDP_LOCK(ddp); + at_pcbdisconnect(ddp); + DDP_UNLOCK(ddp); + soisdisconnected(so); +} + +void +ddp_init(void) +{ + + DDP_LIST_LOCK_INIT(); + TAILQ_INIT(&at_ifaddrhead); + netisr_register(&atalk1_nh); + netisr_register(&atalk2_nh); + netisr_register(&aarp_nh); +} + +#if 0 +static void +ddp_clean(void) +{ + struct ddpcp *ddp; + + for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next) + at_pcbdetach(ddp->ddp_socket, ddp); + DDP_LIST_LOCK_DESTROY(); +} +#endif + +static int +at_getpeeraddr(struct socket *so, struct sockaddr **nam) +{ + + return (EOPNOTSUPP); +} + +static int +at_getsockaddr(struct socket *so, struct sockaddr **nam) +{ + struct ddpcb *ddp; + + ddp = sotoddpcb(so); + KASSERT(ddp != NULL, ("at_getsockaddr: ddp == NULL")); + + DDP_LOCK(ddp); + at_sockaddr(ddp, nam); + DDP_UNLOCK(ddp); + return (0); +} + +struct pr_usrreqs ddp_usrreqs = { + .pru_abort = ddp_abort, + .pru_attach = ddp_attach, + .pru_bind = ddp_bind, + .pru_connect = ddp_connect, + .pru_control = at_control, + .pru_detach = ddp_detach, + .pru_disconnect = ddp_disconnect, + .pru_peeraddr = at_getpeeraddr, + .pru_send = ddp_send, + .pru_shutdown = ddp_shutdown, + .pru_sockaddr = at_getsockaddr, + .pru_close = ddp_close, +}; diff --git a/freebsd/netatalk/ddp_var.h b/freebsd/netatalk/ddp_var.h new file mode 100644 index 00000000..e0148a24 --- /dev/null +++ b/freebsd/netatalk/ddp_var.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 1990, 1994 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * + * $FreeBSD$ + */ + +#ifndef _NETATALK_DDP_VAR_HH_ +#define _NETATALK_DDP_VAR_HH_ + +struct ddpcb { + struct sockaddr_at ddp_fsat, ddp_lsat; + struct route ddp_route; + struct socket *ddp_socket; + struct ddpcb *ddp_prev, *ddp_next; + struct ddpcb *ddp_pprev, *ddp_pnext; + struct mtx ddp_mtx; +}; + +#define sotoddpcb(so) ((struct ddpcb *)(so)->so_pcb) + +struct ddpstat { + long ddps_short; /* short header packets received */ + long ddps_long; /* long header packets received */ + long ddps_nosum; /* no checksum */ + long ddps_badsum; /* bad checksum */ + long ddps_tooshort; /* packet too short */ + long ddps_toosmall; /* not enough data */ + long ddps_forward; /* packets forwarded */ + long ddps_encap; /* packets encapsulated */ + long ddps_cantforward; /* packets rcvd for unreachable dest */ + long ddps_nosockspace; /* no space in sockbuf for packet */ +}; + +#ifdef _KERNEL +extern int ddp_cksum; +extern struct ddpcb *ddpcb_list; +extern struct pr_usrreqs ddp_usrreqs; +extern struct mtx ddp_list_mtx; +#endif + +#endif /* _NETATALK_DDP_VAR_HH_ */ diff --git a/freebsd/netatalk/endian.h b/freebsd/netatalk/endian.h new file mode 100644 index 00000000..b15332c1 --- /dev/null +++ b/freebsd/netatalk/endian.h @@ -0,0 +1,31 @@ +/*- + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Mike Clark + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-763-0525 + * netatalk@itd.umich.edu + * + * $FreeBSD$ + */ + +#ifndef _ATALK_ENDIAN_HH_ +#define _ATALK_ENDIAN_HH_ + +#include <freebsd/machine/endian.h> + +#endif /* !_ATALK_ENDIAN_HH_ */ diff --git a/freebsd/netatalk/phase2.h b/freebsd/netatalk/phase2.h new file mode 100644 index 00000000..aaa3dd38 --- /dev/null +++ b/freebsd/netatalk/phase2.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 1990,1991 Regents of The University of Michigan. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation, and that the name of The University + * of Michigan not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. This software is supplied as is without expressed or + * implied warranties of any kind. + * + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * + * Research Systems Unix Group + * The University of Michigan + * c/o Wesley Craig + * 535 W. William Street + * Ann Arbor, Michigan + * +1-313-764-2278 + * netatalk@umich.edu + * $FreeBSD$ + */ + +#include <freebsd/net/if_llc.h> + +#define llc_org_code llc_un.type_snap.org_code +#define llc_ether_type llc_un.type_snap.ether_type + +#define SIOCPHASE1 _IOW('i', 100, struct ifreq) /* AppleTalk phase 1 */ +#define SIOCPHASE2 _IOW('i', 101, struct ifreq) /* AppleTalk phase 2 */ |