/*
 * (llc_rout.c)- Incoming MAC PDUs are forwarded to appropriate SAP or to 
 * 	station; function called from OS signal.
 *
 * Copyright (c) 1997 by Procom Technology,Inc.
 *
 * This program can be redistributed or modified under the terms of the 
 * GNU General Public License as published by the Free Software Foundation.
 * This program is distributed without any warranty or implied warranty
 * of merchantability or fitness for a particular purpose.
 *
 * See the GNU General Public License for more details.
 *
 */
 

#define LLC_ROUT_C

#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <net/cm_types.h>
#include <net/cm_mm.h>
#include <net/cm_dll.h>
#include <net/cm_frame.h>
#include <net/llc_if.h>
#include <net/llc_sap.h>
#include <net/llc_conn.h>
#include <net/llc_main.h>
#include <net/llc_evnt.h>
#include <net/llc_main.h>
#include <net/llc_mac.h>
#include <net/lan_hdrs.h>
#include <net/llc_pdu.h>
#include <net/llc_c_ev.h>
#include <net/llc_s_ev.h>
#include <net/llc_rout.h>
#include <net/llc_glob.h>
#include <net/llc_dbg.h>

#ifdef LLC_ROUT_DBG
  #define  DBG_MSG(body) { printk body; }
#else
  #define  DBG_MSG(body)  ;
#endif

/*
 * Function: llc_pdu_router
 * 
 * Description:
 *  Queues received PDUs from LLC_MAC PDU receive queue until queue is empty;
 *  examines LLC header to determine the destination of PDU, if DSAP is NULL
 *  then data unit destined for station else frame destined for SAP or 
 *  connection; finds a matching open SAP, if one, forwards the packet to it;
 *  If no matching SAP, drops the packet. 
 *
 * Parameters:
 *  sap_t *sap : This argument points to current sap component structure.
 *  connection_t *conn : This argument points to current connection structure.
 *  frame_t *frame : This argument points to received frame.
 *  us8 type : This argument is type of received frame, that is TYPE_1 or 
 *  	       TYPE_2
 *
 * Returns:
 *  None
 */
 
void 
llc_pdu_router (sap_t *sap, connection_t *conn, frame_t *frame, us8 type)
{
	us16 rc;
	station_t *station;
	pdu_sn_t  *pdu;
	station_state_event_t *stat_event;
	sap_state_event_t *sap_event;
	conn_state_event_t *conn_event;

	pdu = (pdu_sn_t *) frame->llc_hdr;
	if (!pdu->dsap) {
		station_get (&station);
		rc = station_get_event (station, (void **) &stat_event);
		if (!rc) {
			stat_event->type = STATION_EV_TYPE_PDU;
			stat_event->data.pdu.frame = frame;
			stat_event->data.pdu.reason = 0;
			rc = station_send_event(station, (void *) stat_event);
		}
	} else {
		switch (type) {

			case TYPE_1:
				rc = sap_get_event (sap, (void **) &sap_event);
				if (!rc) {
					sap_event->type = SAP_EV_TYPE_PDU;
					sap_event->data.pdu.frame = frame;
					sap_event->data.pdu.reason = 0;
					rc = sap_send_event (sap, 
							(void *) sap_event);
				} else {
					FDBG_ERR_MSG(("\n llc_pdu_router : 
						TYPE_1 no event!!!\n"));
				}
				break;

			case TYPE_2:
				if ( !conn->local_dev )
					conn->local_dev = frame->dev;
				rc = conn_get_event (conn, 
						(void **) &conn_event);
				if (!rc) {
					conn_event->type = CONN_EV_TYPE_PDU;
					conn_event->data.pdu.frame = frame;
					conn_event->data.pdu.reason = 0;
					rc = conn_send_event (conn,
							(void *) conn_event);
				} else {
					FDBG_ERR_MSG(("\n llc_pdu_router : 
						TYPE_2 no event!!!\n"));
				}
				break;
			default:
				break;
		}
	}
	return;
}
