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