1*61eb327bSbloom /*	raw_pup.c	6.2	84/08/29	*/
285b7c5abSsam 
3*61eb327bSbloom #include "param.h"
4*61eb327bSbloom #include "mbuf.h"
5*61eb327bSbloom #include "socket.h"
6*61eb327bSbloom #include "protosw.h"
7*61eb327bSbloom #include "socketvar.h"
8*61eb327bSbloom #include "errno.h"
96d459f86Ssam 
106d459f86Ssam #include "../net/if.h"
1104cfbbb1Ssam #include "../net/route.h"
1204cfbbb1Ssam #include "../net/raw_cb.h"
136d459f86Ssam 
14a6bc5c30Swnj #include "../netpup/pup.h"
1585b7c5abSsam 
1685b7c5abSsam /*
1785b7c5abSsam  * Raw PUP protocol interface.
1885b7c5abSsam  */
1985b7c5abSsam 
2004cfbbb1Ssam struct	sockaddr_pup pupsrc = { AF_PUP };
2104cfbbb1Ssam struct	sockaddr_pup pupdst = { AF_PUP };
2204cfbbb1Ssam struct	sockproto pupproto = { PF_PUP };
2304cfbbb1Ssam /*
2404cfbbb1Ssam  * Raw PUP input.
2504cfbbb1Ssam  */
2604cfbbb1Ssam rpup_input(m)
2704cfbbb1Ssam 	struct mbuf *m;
2804cfbbb1Ssam {
2904cfbbb1Ssam 	register struct pup_header *pup = mtod(m, struct pup_header *);
3004cfbbb1Ssam 
3104cfbbb1Ssam 	pupproto.sp_protocol = pup->pup_type;
3204cfbbb1Ssam 	bcopy((caddr_t)&pup->pup_dnet, (caddr_t)&pupdst.spup_net,
3304cfbbb1Ssam 	    sizeof (struct pupport));
3404cfbbb1Ssam 	bcopy((caddr_t)&pup->pup_snet, (caddr_t)&pupsrc.spup_net,
3504cfbbb1Ssam 	    sizeof (struct pupport));
3604cfbbb1Ssam 	raw_input(m, &pupproto, (struct sockaddr *)&pupsrc,
3704cfbbb1Ssam 	  (struct sockaddr *)&pupdst);
3804cfbbb1Ssam }
3904cfbbb1Ssam 
4085b7c5abSsam /*
4185b7c5abSsam  * Encapsulate packet in PUP header which is supplied by the
4285b7c5abSsam  * user.  This is done to allow user to specify PUP identifier.
4385b7c5abSsam  */
rpup_output(m,so)44a03fe46fSwnj rpup_output(m, so)
45a03fe46fSwnj 	register struct mbuf *m;
4685b7c5abSsam 	struct socket *so;
4785b7c5abSsam {
4885b7c5abSsam 	register struct rawcb *rp = sotorawcb(so);
4985b7c5abSsam 	register struct pup_header *pup;
506dd8a415Ssam 	int len, error = 0;
518a7d1566Ssam 	register struct mbuf *n, *last;
526dd8a415Ssam 	struct sockaddr_pup *dst;
538583c8cbSsam 	struct ifnet *ifp;
5404cfbbb1Ssam 	u_short *pc;
5585b7c5abSsam 
5685b7c5abSsam 	/*
5785b7c5abSsam 	 * Verify user has supplied necessary space
5885b7c5abSsam 	 * for the header and check parameters in it.
5985b7c5abSsam 	 */
6085b7c5abSsam 	if ((m->m_off > MMAXOFF || m->m_len < sizeof(struct pup_header)) &&
616dd8a415Ssam 	    (m = m_pullup(m, sizeof(struct pup_header))) == 0) {
628a7d1566Ssam 		error = EINVAL;
6385b7c5abSsam 		goto bad;
646dd8a415Ssam 	}
6585b7c5abSsam 	pup = mtod(m, struct pup_header *);
668a7d1566Ssam 	if (pup->pup_type == 0 || (pup->pup_tcontrol &~ PUP_TRACE)) {
678a7d1566Ssam 		error = EINVAL;
6885b7c5abSsam 		goto bad;
696dd8a415Ssam 	}
708a7d1566Ssam 	for (len = 0, n = last = m; n; last = n, n = n->m_next)
7185b7c5abSsam 		len += n->m_len;
728a7d1566Ssam 	/* assume user leaves space for checksum */
738a7d1566Ssam 	if ((len & 1) || len < MINPUPSIZ || len > MAXPUPSIZ) {
748a7d1566Ssam 		error = EMSGSIZE;
758a7d1566Ssam 		goto bad;
768a7d1566Ssam 	}
773969fee3Ssam 	pup->pup_length = htons((u_short)len);
786dd8a415Ssam 	dst = (struct sockaddr_pup *)&rp->rcb_faddr;
7904cfbbb1Ssam 	bcopy((caddr_t)&dst->spup_net, (caddr_t)&pup->pup_dnet,
808a7d1566Ssam 	    sizeof (struct pupport));
8104cfbbb1Ssam 	if (rp->rcb_route.ro_rt == 0)
8204cfbbb1Ssam 		ifp = if_ifonnetof(dst->spup_net);
8304cfbbb1Ssam 	else {
8404cfbbb1Ssam 		rp->rcb_route.ro_rt->rt_use++;
8504cfbbb1Ssam 		ifp = rp->rcb_route.ro_rt->rt_ifp;
8604cfbbb1Ssam 	}
878a7d1566Ssam 	if (ifp == 0) {
888a7d1566Ssam 		error = ENETUNREACH;
898a7d1566Ssam 		goto bad;
908a7d1566Ssam 	}
916dd8a415Ssam 	if (rp->rcb_flags & RAW_LADDR) {
926dd8a415Ssam 		register struct sockaddr_pup *src;
9385b7c5abSsam 
946dd8a415Ssam 		src = (struct sockaddr_pup *)&rp->rcb_laddr;
9504cfbbb1Ssam 		bcopy((caddr_t)&src->spup_net, (caddr_t)&pup->pup_snet,
968a7d1566Ssam 		    sizeof (struct pupport));
976dd8a415Ssam 	} else {
986dd8a415Ssam 		pup->pup_snet = ifp->if_net;
996dd8a415Ssam 		pup->pup_shost = ifp->if_host[0];
1006dd8a415Ssam 		/* socket is specified by user */
1016dd8a415Ssam 	}
1028a7d1566Ssam 	/*
1038a7d1566Ssam 	 * Fill in checksum unless user indicates none should be specified.
1048a7d1566Ssam 	 */
10504cfbbb1Ssam 	pc = (u_short *)(mtod(last, caddr_t) + last->m_len - sizeof (short));
10604cfbbb1Ssam 	if (*pc != PUP_NOCKSUM)
107b487a6ceSsam 		*pc = htons((u_short)pup_cksum(m, len - sizeof (short)));
1086dd8a415Ssam 	return ((*ifp->if_output)(ifp, m, (struct sockaddr *)dst));
10985b7c5abSsam bad:
11085b7c5abSsam 	m_freem(m);
1116dd8a415Ssam 	return (error);
11285b7c5abSsam }
113