diff --git a/session_test.go b/session_test.go
index 786a661..7e8e129 100644
--- a/session_test.go
+++ b/session_test.go
@@ -199,6 +199,9 @@ func TestPty(t *testing.T) {
 	term := "xterm"
 	winWidth := 40
 	winHeight := 80
+	TerminalModes := make(gossh.TerminalModes)
+	ttyOPOSPEED := uint32(38400)
+	TerminalModes[gossh.TTY_OP_OSPEED] = ttyOPOSPEED
 	done := make(chan bool)
 	session, _, cleanup := newTestSession(t, &Server{
 		Handler: func(s Session) {
@@ -215,11 +218,15 @@ func TestPty(t *testing.T) {
 			if ptyReq.Window.Height != winHeight {
 				t.Fatalf("expected window height %#v but got %#v", winHeight, ptyReq.Window.Height)
 			}
+			mode := ptyReq.TerminalModes[gossh.TTY_OP_OSPEED]
+			if ptyReq.TerminalModes[gossh.TTY_OP_OSPEED] != ttyOPOSPEED {
+				t.Fatalf("expected mode %#v but got %#v", ttyOPOSPEED, mode)
+			}
 			close(done)
 		},
 	}, nil)
 	defer cleanup()
-	if err := session.RequestPty(term, winHeight, winWidth, gossh.TerminalModes{}); err != nil {
+	if err := session.RequestPty(term, winHeight, winWidth, TerminalModes); err != nil {
 		t.Fatalf("expected nil but got %v", err)
 	}
 	if err := session.Shell(); err != nil {
diff --git a/ssh.go b/ssh.go
index 9673ac3..ffe3e94 100644
--- a/ssh.go
+++ b/ssh.go
@@ -72,9 +72,9 @@ type Window struct {
 
 // Pty represents a PTY request and configuration.
 type Pty struct {
-	Term   string
-	Window Window
-	// HELP WANTED: terminal modes!
+	Term          string
+	Window        Window
+	TerminalModes gossh.TerminalModes
 }
 
 // Serve accepts incoming SSH connections on the listener l, creating a new
diff --git a/util.go b/util.go
index 015a44e..a41e7cd 100644
--- a/util.go
+++ b/util.go
@@ -8,6 +8,19 @@ import (
 	"golang.org/x/crypto/ssh"
 )
 
+type ptyRequestMsg struct {
+	Term     string
+	Columns  uint32
+	Rows     uint32
+	Width    uint32
+	Height   uint32
+	Modelist string
+}
+
+const (
+	ttyOPEND = 0
+)
+
 func generateSigner() (ssh.Signer, error) {
 	key, err := rsa.GenerateKey(rand.Reader, 2048)
 	if err != nil {
@@ -17,28 +30,91 @@ func generateSigner() (ssh.Signer, error) {
 }
 
 func parsePtyRequest(s []byte) (pty Pty, ok bool) {
-	term, s, ok := parseString(s)
-	if !ok {
-		return
-	}
-	width32, s, ok := parseUint32(s)
-	if !ok {
+	reqMsg := &ptyRequestMsg{}
+	err := ssh.Unmarshal(s, reqMsg)
+	if err != nil {
 		return
 	}
-	height32, _, ok := parseUint32(s)
+
+	modes := []byte(reqMsg.Modelist)
+	terminalModes, ok := parseTerminalModes(modes)
 	if !ok {
 		return
 	}
+
 	pty = Pty{
-		Term: term,
+		Term: reqMsg.Term,
 		Window: Window{
-			Width:  int(width32),
-			Height: int(height32),
+			Width:  int(reqMsg.Columns),
+			Height: int(reqMsg.Rows),
 		},
+		TerminalModes: terminalModes,
 	}
 	return
 }
 
+func makeTerminalModes(terminalModes ssh.TerminalModes) string {
+	var tm []byte
+	for k, v := range terminalModes {
+		kv := struct {
+			Key byte
+			Val uint32
+		}{k, v}
+
+		tm = append(tm, ssh.Marshal(&kv)...)
+	}
+	tm = append(tm, ttyOPEND)
+	return string(tm)
+}
+
+func parseTerminalModes(s []byte) (terminalModes ssh.TerminalModes, ok bool) {
+	mode := struct {
+		Key uint8
+		Val uint32
+	}{}
+
+	terminalModes = make(ssh.TerminalModes, 0)
+	for {
+		if len(s) < 1 {
+			ok = true
+			return
+		}
+
+		opcode := s[0]
+		switch opcode {
+		case ttyOPEND:
+			ok = true
+			return
+		default:
+			/*
+			 * SSH2:
+			 * Opcodes 1 to 159 are defined to have a uint32
+			 * argument.
+			 * Opcodes 160 to 255 are undefined and cause parsing
+			 * to stop.
+			 */
+			if opcode > 0 && opcode < 160 {
+				if len(s) < 5 {
+					// parse failed
+					return
+				}
+
+				b := s[:5]
+				if err := ssh.Unmarshal(b, &mode); err != nil {
+					return
+				}
+
+				terminalModes[mode.Key] = mode.Val
+				s = s[6:]
+
+			} else {
+				ok = true
+				return
+			}
+		}
+	}
+}
+
 func parseWinchRequest(s []byte) (win Window, ok bool) {
 	width32, s, ok := parseUint32(s)
 	if width32 < 1 {