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