1*8a7d1566Ssam /*	raw_pup.c	4.17	83/05/30	*/
285b7c5abSsam 
385b7c5abSsam #include "../h/param.h"
485b7c5abSsam #include "../h/mbuf.h"
585b7c5abSsam #include "../h/socket.h"
685b7c5abSsam #include "../h/protosw.h"
785b7c5abSsam #include "../h/socketvar.h"
86d459f86Ssam #include "../h/errno.h"
96d459f86Ssam 
106d459f86Ssam #include "../net/if.h"
116d459f86Ssam 
12a6bc5c30Swnj #include "../netpup/pup.h"
1385b7c5abSsam #include "../net/raw_cb.h"
1485b7c5abSsam 
1585b7c5abSsam /*
1685b7c5abSsam  * Raw PUP protocol interface.
1785b7c5abSsam  */
1885b7c5abSsam 
1985b7c5abSsam /*
2085b7c5abSsam  * Encapsulate packet in PUP header which is supplied by the
2185b7c5abSsam  * user.  This is done to allow user to specify PUP identifier.
2285b7c5abSsam  */
23a03fe46fSwnj rpup_output(m, so)
24a03fe46fSwnj 	register struct mbuf *m;
2585b7c5abSsam 	struct socket *so;
2685b7c5abSsam {
2785b7c5abSsam 	register struct rawcb *rp = sotorawcb(so);
2885b7c5abSsam 	register struct pup_header *pup;
296dd8a415Ssam 	int len, error = 0;
30*8a7d1566Ssam 	register struct mbuf *n, *last;
316dd8a415Ssam 	struct sockaddr_pup *dst;
328583c8cbSsam 	struct ifnet *ifp;
33*8a7d1566Ssam 	u_short *pchecksum;
3485b7c5abSsam 
3585b7c5abSsam 	/*
3685b7c5abSsam 	 * Verify user has supplied necessary space
3785b7c5abSsam 	 * for the header and check parameters in it.
3885b7c5abSsam 	 */
3985b7c5abSsam 	if ((m->m_off > MMAXOFF || m->m_len < sizeof(struct pup_header)) &&
406dd8a415Ssam 	    (m = m_pullup(m, sizeof(struct pup_header))) == 0) {
41*8a7d1566Ssam 		error = EINVAL;
4285b7c5abSsam 		goto bad;
436dd8a415Ssam 	}
4485b7c5abSsam 	pup = mtod(m, struct pup_header *);
45*8a7d1566Ssam 	if (pup->pup_type == 0 || (pup->pup_tcontrol &~ PUP_TRACE)) {
46*8a7d1566Ssam 		error = EINVAL;
4785b7c5abSsam 		goto bad;
486dd8a415Ssam 	}
49*8a7d1566Ssam 	for (len = 0, n = last = m; n; last = n, n = n->m_next)
5085b7c5abSsam 		len += n->m_len;
51*8a7d1566Ssam 	/* assume user leaves space for checksum */
52*8a7d1566Ssam 	if ((len & 1) || len < MINPUPSIZ || len > MAXPUPSIZ) {
53*8a7d1566Ssam 		error = EMSGSIZE;
54*8a7d1566Ssam 		goto bad;
55*8a7d1566Ssam 	}
56*8a7d1566Ssam 	pup->pup_length = htons(len);
576dd8a415Ssam 	dst = (struct sockaddr_pup *)&rp->rcb_faddr;
58*8a7d1566Ssam 	bcopy((caddr_t)dst->spup_net, (caddr_t)pup->pup_dnet,
59*8a7d1566Ssam 	    sizeof (struct pupport));
60*8a7d1566Ssam 	ifp = if_ifonnetof((u_int)pup->pup_dnet);
61*8a7d1566Ssam 	if (ifp == 0) {
62*8a7d1566Ssam 		error = ENETUNREACH;
63*8a7d1566Ssam 		goto bad;
64*8a7d1566Ssam 	}
656dd8a415Ssam 	if (rp->rcb_flags & RAW_LADDR) {
666dd8a415Ssam 		register struct sockaddr_pup *src;
6785b7c5abSsam 
686dd8a415Ssam 		src = (struct sockaddr_pup *)&rp->rcb_laddr;
69*8a7d1566Ssam 		bcopy((caddr_t)src->spup_net, (caddr_t)pup->pup_snet,
70*8a7d1566Ssam 		    sizeof (struct pupport));
716dd8a415Ssam 	} else {
726dd8a415Ssam 		pup->pup_snet = ifp->if_net;
736dd8a415Ssam 		pup->pup_shost = ifp->if_host[0];
746dd8a415Ssam 		/* socket is specified by user */
756dd8a415Ssam 	}
76*8a7d1566Ssam 	/*
77*8a7d1566Ssam 	 * Fill in checksum unless user indicates none should be specified.
78*8a7d1566Ssam 	 */
79*8a7d1566Ssam 	pchecksum =
80*8a7d1566Ssam 	    (u_short *)(mtod(last, caddr_t) + last->m_len - sizeof (short));
81*8a7d1566Ssam 	if (*pchecksum != PUP_NOCKSUM)
82*8a7d1566Ssam 		*pchecksum = pup_cksum(m, len - sizeof (short));
836dd8a415Ssam 	return ((*ifp->if_output)(ifp, m, (struct sockaddr *)dst));
8485b7c5abSsam bad:
8585b7c5abSsam 	m_freem(m);
866dd8a415Ssam 	return (error);
8785b7c5abSsam }
88