# /* in_write.c */ /* EMACS_MODES: c !fill */ /* Internet protocol layer for the MIT network system. The following * routines are included: * in_write Write a packet out to an internet connection * * Note that use of this package requires the use of the standard I/O * library. */ #include #include #include #include #include in_write (fd, buf, datalen) /* Write the specified packet to the net. The buf argument is a * pointer to the start of a packet buffer, such as one allocated * by in_alloc. The packet buffer is assumed to have space at * the beginning for local net and internet headers. It is also * assumed that there is enough space in the packet buffer to * pad the packet up to an even number of bytes, because all * transmitted packets must be an even number of bytes in * length. (If the packet was obtained by in_alloc or by * in_read this will be the case). * The caller is assumed to have filled in the foreign host address, * protocol, internet packet id, and type of service fields in the * internet header, as well as any option fields. A zero in the * internet packet id field will result in its being filled with * a unique value. The internet header length field is * assumed to have been filled in by the packet's allocator (for * example, in_alloc ()). * This routine fills in the remainder of the internet header. * Returns the number of bytes written if successful; if not, * returns -1 and the system error code in global errno. * * Arguments: */ int fd; /* file descriptor for this conn */ caddr_t buf; /* pointer to start of pkt */ int datalen; /* length of data portion of pkt */ { reg struct ip *pip; /* ptr. to internet hdr. of pkt */ reg struct ip *pip2; /* ptr to in hdr of frag buffer */ reg int len; /* total packet length */ int stat; /* write status */ int dlen; /* data length of fragment */ int tlen; /* total packet length */ int hdsiz; /* header length */ int offset; /* offset of frag from start of pkt */ int maxfsz; /* maximum frag size for conn */ int more; /* more fragments flag */ caddr_t fbuf; /* fragmentation buffer */ caddr_t pfrom; /* data copy from pointer */ caddr_t pto; /* data copy to pointer */ pip = in_head(buf); /* find IN header */ pip->ip_ver = IP_VER; pip->ip_time = IP_TIME; pip->ip_chksum = CHKSUM; /* and checksum */ pip->ip_src = 0L; /* kernel fills local address */ hdsiz = pip->ip_ihl << 2; /* get various data sizes */ maxfsz = in_frgbuf[fd].fg_size - hdsiz; /* max data fragment */ maxfsz &= ~(FRAGGRAIN - 1); /* round down to granularity */ fbuf = in_frgbuf[fd].fg_buf; /* ptr to frag buffer */ len = datalen; if (len > maxfsz) { /* fragmentation needed? */ len = maxfsz; /* yep */ more = 1; /* show it */ movem (buf, fbuf, lnhsiz + hdsiz); /* copy hdr into frag buf */ } else more = 0; /* no fragmentation needed */ tlen = lnhsiz + hdsiz + ((len + 1) & ~1) + lntsiz; /* total length */ pip->ip_len = len + hdsiz; /* in packet length */ pip->ip_foff = 0; /* offset of 0 */ pip->ip_flgs = more; /* fragmentation info */ #ifndef BIGINDIAN ipswab (pip); /* if needed, swap integer fields */ #endif #ifdef DEBUG in_logpkt (buf, len, OUTPKT); #endif do { /* write it out */ stat = write (fd, buf, tlen); } while (stat < tlen && errno == EINTR); if (stat < tlen) return (-1); pip->ip_id = short_to_net (pip->ip_id); /* byte-swap id field */ if (!more) return (datalen); /* Fragmentation needed; copy each frag to frag buffer and send it */ pip2 = in_head (fbuf); /* in header of frag buffer */ pto = in_data (pip2); /* data part of frag buffer */ dlen = datalen - len; /* remaining data length */ for (pfrom = in_data (pip) + len, offset = len; dlen > 0; pfrom += len, offset += len, dlen -= len) { len = dlen; if (len > maxfsz) { /* yet more fragments? */ len = maxfsz; more = 1; } else more = 0; /* no more... */ tlen = lnhsiz + hdsiz + ((len + 1) & ~1) + lntsiz; movem (pfrom, pto, len); /* copy data in to frag buffer */ pip2->ip_id = pip->ip_id; /* get id */ pip2->ip_chksum = CHKSUM; /* zero checksum field */ pip2->ip_len = len + hdsiz; pip2->ip_foff = offset >> 3; /* fragment offset */ pip2->ip_flgs = more; /* more fragments? */ #ifndef BIGINDIAN ipswab (pip2); #endif #ifdef DEBUG in_logpkt (fbuf, len, OUTPKT); #endif do { /* write it out */ stat = write (fd, fbuf, tlen); } while (stat < tlen && errno == EINTR); if (stat < tlen) return (-1); } return (datalen); } #ifndef BIGINDIAN ipswab( ppkt ) /* * Swap bytes in integer fields (except sumcheck fields) * of internet packet. */ struct ip *ppkt; /* ptr. to internet hdr. of pkt */ { static int swabds[] = { &0->ip_len, &0->ip_id, (&0->ip_id) + 1, }; swaba( (char *)ppkt, swabds, (sizeof(swabds)/sizeof(swabds[0]))); return; } #endif