drv_dep.c   [plain text]


/*
 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * Copyright 1994 Apple Computer, Inc.
 * All Rights Reserved.
 *
 * Tuyen A. Nguyen. (December 5, 1994)
 *   Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
 */

#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <machine/spl.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/filedesc.h>
#include <sys/fcntl.h>
#include <sys/mbuf.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sockio.h>

#include <net/if.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <net/ethernet.h>

#include <netat/sysglue.h>
#include <netat/appletalk.h>
#include <netat/at_pcb.h>
#include <netat/at_var.h>
#include <netat/ddp.h>
#include <netat/at_aarp.h>
#include <netat/at_pat.h>
#include <netat/debug.h>

#define DSAP_SNAP 0xaa

extern void gref_init(), atp_init(), atp_link(), atp_unlink();

extern int adspInited;

static llc_header_t	snap_hdr_at = SNAP_HDR_AT;
static llc_header_t	snap_hdr_aarp = SNAP_HDR_AARP;
static unsigned char snap_proto_ddp[5] = SNAP_PROTO_AT;
static unsigned char snap_proto_aarp[5] = SNAP_PROTO_AARP;

static void at_input_packet(protocol_family_t protocol, mbuf_t m);

int pktsIn, pktsOut;

struct ifqueue atalkintrq; 	/* appletalk and aarp packet input queue */

short appletalk_inited = 0;

extern atlock_t 
	ddpall_lock, ddpinp_lock, arpinp_lock, refall_lock, nve_lock,
  	aspall_lock, asptmo_lock, atpall_lock, atptmo_lock, atpgen_lock;

extern int (*sys_ATsocket )(), (*sys_ATgetmsg)(), (*sys_ATputmsg)();
extern int (*sys_ATPsndreq)(), (*sys_ATPsndrsp)();
extern int (*sys_ATPgetreq)(), (*sys_ATPgetrsp)();

void atalk_load()
{
	extern int _ATsocket(), _ATgetmsg(), _ATputmsg();
	extern int _ATPsndreq(), _ATPsndrsp(), _ATPgetreq(), _ATPgetrsp();
	extern lck_mtx_t *domain_proto_mtx;

	sys_ATsocket  = _ATsocket;
	sys_ATgetmsg  = _ATgetmsg;
	sys_ATputmsg  = _ATputmsg;
	sys_ATPsndreq = _ATPsndreq;
	sys_ATPsndrsp = _ATPsndrsp;
	sys_ATPgetreq = _ATPgetreq;
	sys_ATPgetrsp = _ATPgetrsp;

	ATLOCKINIT(ddpall_lock);
	ATLOCKINIT(ddpinp_lock);
	ATLOCKINIT(arpinp_lock);
	ATLOCKINIT(refall_lock);
	ATLOCKINIT(aspall_lock);
	ATLOCKINIT(asptmo_lock);
	ATLOCKINIT(atpall_lock);
	ATLOCKINIT(atptmo_lock);
	ATLOCKINIT(atpgen_lock);
	ATLOCKINIT(nve_lock);

	atp_init();
	atp_link();
	adspInited = 0;

/*	adsp_init(); 
		for 2225395
		this happens in adsp_open and is undone on ADSP_UNLINK 
*/
	lck_mtx_unlock(domain_proto_mtx);
	proto_register_input(PF_APPLETALK, at_input_packet, NULL);
	lck_mtx_lock(domain_proto_mtx);
} /* atalk_load */

/* Undo everything atalk_load() did. */
void atalk_unload()  /* not currently used */
{
	extern gbuf_t *scb_resource_m;
	extern gbuf_t *atp_resource_m;

	sys_ATsocket  = 0;
	sys_ATgetmsg  = 0;
	sys_ATputmsg  = 0;
	sys_ATPsndreq = 0;
	sys_ATPsndrsp = 0;
	sys_ATPgetreq = 0;
	sys_ATPgetrsp = 0;

	atp_unlink();

#ifdef NOT_YET
	if (scb_resource_m) { 
		gbuf_freem(scb_resource_m);
		scb_resource_m = 0;
		scb_free_list = 0;
	}
	/* allocated in atp_trans_alloc() */
	if (atp_resource_m) {
		gbuf_freem(atp_resource_m);
		atp_resource_m = 0;
		atp_trans_free_list = 0;
	}
#endif

	appletalk_inited = 0;
} /* atalk_unload */

void appletalk_hack_start()
{
	if (!appletalk_inited) {
		atalk_load();
		atalkintrq.ifq_maxlen = IFQ_MAXLEN; 
		appletalk_inited = 1;
	}
} /* appletalk_hack_start */

int pat_output(patp, mlist, dst_addr, type)
	at_ifaddr_t *patp;
	struct mbuf *mlist;			/* packet chain */
	unsigned char *dst_addr;
	int 	type;
{
	struct mbuf *m, *m1;
	llc_header_t *llc_header;
	struct sockaddr dst;

	if (! patp->aa_ifp) {
		for (m = mlist; m; m = mlist) {
			mlist = m->m_nextpkt;
			m->m_nextpkt = 0;
			m_freem(m);
		}
		return ENOTREADY;
	}

	/* this is for ether_output */
	dst.sa_family = AF_APPLETALK;
	dst.sa_len = 2 + sizeof(struct etalk_addr);
	bcopy (dst_addr, &dst.sa_data[0], sizeof(struct etalk_addr)); 

	/* packet chains are used on output and can be tested using aufs */
	for (m = mlist; m; m = mlist) {
		mlist = m->m_nextpkt;
		m->m_nextpkt = 0;

		M_PREPEND(m, sizeof(llc_header_t), M_DONTWAIT);
		if (m == 0) {
			continue;
		}

		llc_header = mtod(m, llc_header_t *);
		*llc_header = 
		  (type == AARP_AT_TYPE) ? snap_hdr_aarp : snap_hdr_at;

		for (m->m_pkthdr.len = 0, m1 = m; m1; m1 = m1->m_next)
			m->m_pkthdr.len += m1->m_len;
		m->m_pkthdr.rcvif = 0;

		/* *** Note: AT is sending out mbufs of type MSG_DATA,
		   not MT_DATA.  *** */
#ifdef APPLETALK_DEBUG
		if (m->m_next && 
		    !((m->m_next)->m_flags & M_EXT))
			kprintf("po: mlen= %d, m2len= %d\n", m->m_len, 
				(m->m_next)->m_len);
#endif
		atalk_unlock();
		dlil_output(patp->aa_ifp, PF_APPLETALK, m, NULL, &dst, 0);
		atalk_lock();

		pktsOut++;
	}

	return 0;
} /* pat_output */

static void
at_input_packet(
	__unused protocol_family_t	protocol,
	mbuf_t						m)
{
	struct mbuf *m1;
	struct ifnet *ifp;
	llc_header_t *llc_header;
	at_ifaddr_t *ifID;
	char src[6];
	enet_header_t *enet_header;

	if (!appletalk_inited) {
		m_freem(m);
		return;
	}

	if ((m->m_flags & M_PKTHDR) == 0) {
#ifdef APPLETALK_DEBUG
		kprintf("atalkintr: no HDR on packet received");
#endif
		m_freem(m);
		return;
	}

	  /* make sure the interface this packet was received on is configured
	     for AppleTalk */
	  ifp = m->m_pkthdr.rcvif;
	  TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
		if (ifID->aa_ifp && (ifID->aa_ifp == ifp)) 
			break;
	  }
	  /* if we didn't find a matching interface */
	  if (!ifID) {
		m_freem(m);
		return; /* was EAFNOSUPPORT */
	  }

	  /* make sure the entire packet header is in the current mbuf */
	  if (m->m_len < ENET_LLC_SIZE &&
	      (m = m_pullup(m, ENET_LLC_SIZE)) == 0) {
#ifdef APPLETALK_DEBUG
		kprintf("atalkintr: packet too small\n");
#endif
		m_freem(m);
		return;
	  }
	  enet_header = mtod(m, enet_header_t *);

	  /* Ignore multicast packets from local station */
	  /* *** Note: code for IFTYPE_TOKENTALK may be needed here. *** */
	  if (ifID->aa_ifp->if_type == IFT_ETHER ||
		ifID->aa_ifp->if_type == IFT_L2VLAN ||
		ifID->aa_ifp->if_type == IFT_IEEE8023ADLAG) {
		bcopy((char *)enet_header->src, src, sizeof(src));

#ifdef COMMENT  /* In order to receive packets from the Blue Box, we cannot 
		   reject packets whose source address matches our local address.
		*/
		if ((enet_header->dst[0] & 1) && 
		    (bcmp(src, ifID->xaddr, sizeof(src)) == 0)) {
		  /* Packet rejected: think it's a local mcast. */
		  m_freem(m);
		  return; /* was EAFNOSUPPORT */
		}
#endif /* COMMENT */

		llc_header = (llc_header_t *)(enet_header+1);

		/* advance the mbuf pointers past the ethernet header */
		m->m_data += ENET_LLC_SIZE;
		m->m_len -= ENET_LLC_SIZE;

		pktsIn++;

		if (LLC_PROTO_EQUAL(llc_header->protocol,snap_proto_aarp)) {
	       		(void)aarp_rcv_pkt(mtod(m, aarp_pkt_t *), ifID);
			m_freem(m);
		} 
		else if (LLC_PROTO_EQUAL(llc_header->protocol, snap_proto_ddp)) {
			/* if we're a router take all pkts */
			if (!ROUTING_MODE) {
			  if (aarp_chk_addr(mtod(m, at_ddp_t  *), ifID)
			      == AARP_ERR_NOT_OURS) {
#ifdef APPLETALK_DEBUG
			    kprintf("pat_input: Packet Rejected: not for us? dest=%x.%x.%x.%x.%x.%x LLC_PROTO= %02x%02x\n",
				    enet_header->dst[0], enet_header->dst[1], 
				    enet_header->dst[2], enet_header->dst[3], 
				    enet_header->dst[4], enet_header->dst[5], 
				    llc_header->protocol[3],
				    llc_header->protocol[4]);
#endif
			    m_freem(m);
			    return; /* was EAFNOSUPPORT */
			  }
			}
			MCHTYPE(m, MSG_DATA); /* set the mbuf type */

			ifID->stats.rcv_packets++;
			for (m1 = m; m1; m1 = m1->m_next)
				ifID->stats.rcv_bytes += m1->m_len;

			if (!MULTIPORT_MODE)
				ddp_glean(m, ifID, src);

			ddp_input(m, ifID);
		} else {
#ifdef APPLETALK_DEBUG
		  	kprintf("pat_input: Packet Rejected: wrong LLC_PROTO = %02x%02x\n",
				llc_header->protocol[3],
				llc_header->protocol[4]);
#endif
			m_freem(m);
		}
	}
}