STREAMS Programming Guide

Service Interface Procedure

The write put procedure, protowput(), is shown in the following example:


Example 8–18 Service Interface protoput Procedure

static int protowput(queue_t *q, mblk_t *mp)
{
 	union primitives *proto;
 	struct dgproto *dgproto;
 	int err;
 	dgproto = (struct dgproto *) q->q_ptr;  /* priv data struct */
 	switch (mp->b_datap->db_type) {
 	default:
 			/* don't understand it */
 			mp->b_datap->db_type = M_ERROR;
 			mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
 			*mp->b_wptr++ = EPROTO;
 			qreply(q, mp);
 			break;
 	case M_FLUSH: /* standard flush handling goes here ... */
 			break;
 	case M_PROTO:
 			/* Protocol message -> user request */
 			proto = (union primitives *) mp->b_rptr;
 			switch (proto->type) {
 			default:
 				mp->b_datap->db_type = M_ERROR;
 				mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
 				*mp->b_wptr++ = EPROTO;
 				qreply(q, mp);
 				return;
 			case BIND_REQ:
 				if (dgproto->state != IDLE) {
 						err = EINVAL;
 						goto error_ack;
 				}
 				if (mp->b_wptr - mp->b_rptr !=
 				 sizeof(struct bind_req)) {
 						err = EINVAL;
 						goto error_ack;
 				}
 				if (err = chkaddr(proto->bind_req.BIND_addr))
 						goto error_ack;
 				dgproto->state = BOUND;
 				dgproto->addr = proto->bind_req.BIND_addr;
 				mp->b_datap->db_type = M_PCPROTO;
 				proto->type = OK_ACK;
 				mp->b_wptr=mp->b_rptr+sizeof(structok_ack);
 				qreply(q, mp);
 				break;
			error_ack:
 				mp->b_datap->db_type = M_PCPROTO;
 				proto->type = ERROR_ACK;
 				proto->error_ack.UNIX_error = err;
 				mp->b_wptr = mp->b_rptr+sizeof(structerror_ack);
 				qreply(q, mp);
 				break;
 			case UNITDATA_REQ:
 				if (dgproto->state != BOUND)
 						goto bad;
 				if (mp->b_wptr - mp->b_rptr !=
 					 sizeof(struct unitdata_req))
 						goto bad;
 				if(err=chkaddr(proto->unitdata_req.DEST_addr))
 						goto bad;
 				putq(q, mp);
 				/* start device or mux output ... */
 				break;
 			bad:
 				freemsg(mp);
 				break;
 			}
	 }
return(0);
}

The write put procedure, protowput(), switches on the message type. The only types accepted are M_FLUSH and M_PROTO. For M_FLUSH messages, the driver performs the canonical flush handling (not shown). For M_PROTO messages, the driver assumes that the message block contains a union primitive and switches on the type field. Two types are understood: BIND_REQ and UNITDATA_REQ.

For a BIND_REQ, the current state is checked; it must be IDLE. Next, the message size is checked. If it is the correct size, the passed-in address is verified for legality by calling chkaddr. If everything checks, the incoming message is converted into an OK_ACK and sent upstream. If there was any error, the incoming message is converted into an ERROR_ACK and sent upstream.

For UNITDATA_REQ, the state is also checked; it must be BOUND. As above, the message size and destination address are checked. If there is any error, the message is discarded. If all is well, the message is put in the queue, and the lower half of the driver is started.

If the write put procedure receives a message type that it does not understand, either a bad b_datap->db_type or bad proto->type, the message is converted into an M_ERROR message and is then sent upstream.

The generation of UNITDATA_IND messages (not shown in the example) would normally occur in the device interrupt if this is a hardware driver or in the lower read put procedure if this is a multiplexer. The algorithm is simple: the data part of the message is prefixed by an M_PROTO message block that contains a unitdata_ind structure and is sent upstream.